Advertisement

Re: A Class Definition within another class?

Started by April 26, 2000 11:03 PM
5 comments, last by Mithrandir 24 years, 7 months ago
okay, this is a separate issue from that pure virtual thread, and i don''t want to clutter it up, so im posting a new thread. Now, I didn''t quite understand the importance of the relationships of a class defined within another class. Say i have:

class A
{
    class B
    {
        // blah
    };
};
that doesn''t mean that class A HAS A class B, does it? Im not exactly understanding here, heh. =============================================== "Tell brave deeds of war." Then they recounted tales, -- "There were stern stands And bitter runs for glory." Ah, I think there were braver deeds.
This is my signature. There are many like it, but this one is mine. My signature is my best friend. It is my life. I must master it as I must master my life. My signature, without me, is useless. Without my signature, I am useless.
your close, but that bit of code is useless
it declares class b, but doesnt create one inside class a
on the other hand with a tiny change it would:

class A{	class B	{	} myB;};  


now the class A has a member class of type B called myB
if you dont add a declaration of class B after it then class B is really useless as it only exists in the scope of class A (i think..)
so! this is usually used when myB will be private, if it was public you would have less control over it, you couldn't say:
A exampleA;B temporaryB = NULL; //error, you cant create a B, theres no definition for itexampleA.myB = temporaryB; 


umm i think I might have gotten carried away, Im fairly sure this is all correct at least I hope it helps.

Edited by - Atavist on 4/27/00 12:13:45 AM
Just because the church was wrong doesn't mean Galileo wasn't a heretic.It just means he was a heretic who was right.
Advertisement
The scope of class B is not affected by whether its instantiated or not within the wrapping class. You can instantiate it directly from anywhere using A::B blah; , assuming it is public. If its private, you can still instantiate it directly albeit only from within A''s member functions.

(I'll try better this time, but you probably won't get it as I have an odd way of explaining things.)

A better way of saying that would be to say that B BELONGS_TO A (don't know if that term exists). It's really not much use if you're just using letters -- you need an idea of how it works.

In other words, I have two class definitions: Image, and Sound. I want to make an Effect class for both of them, and I don't need to use an abstract base class because Effect classes need to know the format of the data on which they work -- they're not interchangeable. ImageEffect requires an Image, and SoundEffect requires a Sound. Now, the user of these classes doesn't care how Effect works (i.e., he doesn't care whether it's a SoundEffect, or a ImageEffect). He just knows that they are applied in the same basic way (i.e., they have the same principle).

So, you could do this:


class Sound
{
};

class SoundEffect
{
};

class Image
{
};

class ImageEffect
{
};



But doing it that way is bad, because we cannot limit the use of the Effect-type objects. Anyone can make one, unless we do something silly with the constructors but that's beside the point. It's just not logical. ImageEffect requires an Image to work on, and SoundEffect requires a Sound to work on. You can't really use one apart from the other. The best way to do it is:


class Image
{
protected:
class Effect
{
};
};

class Sound
{
protected:
class Effect
{
};
};



They are declared with the same name, but they are different classes, and they are used by the scope operator, kind of like a namespace: Image::Effect, and Sound::Effect. When you think about it, it really does make it easier to learn how the class works, if you have similar class names for similar purposes.

Anyway, what it means is that you have a class "structure" where the classes are all co-dependent anyway. So, if you want to learn Image, you will pull in Image::Effect, Image::Loader (if you wanted to create it), etc. It's a way of separating one huge Image class into several small objects that work together.

Think of it kind of like a directory structure. You never create several folders side-by-side called MyGame Source, MyGame Debug, MyGame Resources. You would create a MyGame folder, and then place in it folders called Source, Debug, and Resources. You now have MyGame, MyGame\Source, etc. With classes defined within another class, it's the same thing, except that we're using the :: operator.

Also, sometimes we have dependencies, like this:


class Stream
{
public:
class Data
{
public:
// The derived object writes itself
virtual void Serialize(Stream& stream, bool is_reading) = 0;
};

public:
// Allow Stream::Data objects to read and write themselves
operator << (Stream::Data* pData)
{ pData->Serialize(*this, false); }

operator >> (Stream::Data* pData)
{ pData->Serialize(*this, true); }

protected:
// Read and write raw data
Read(void*);
Write(void*);
};



Meaning, if you want to use a Stream object, you derive your class from Stream::Data and override the Serialize function. Then, presto, you can send any class you wish through the << and >> operators and its Serialize function will automatically be called, etc. It's because the Stream class only accepts a certain kind of data, which has a specified function for writing and reading itself. In other words, Stream is guaranteed to either write or read the object successfully, or trigger a compiler error (barring media errors, like EOF, of course). And you can tell all that just by looking at the Stream class.


So, it's a way of describing classes that are dependent on each other and cannnot be used apart. Or, a way of splitting up a big class into smaller, more manageable objects. Just depends on your viewpoint.



- null_pointer
Sabre Multimedia


Edited by - null_pointer on 4/27/00 8:40:19 AM
OH! I think I see now!

okay, basically, defining a class inside another class means that the sub-class is only accessable through the class it is defined in.

So, therefore, we can make sure than an ImageEffect is only used with an Image class.

very interesting.



===============================================
"Tell brave deeds of war."
Then they recounted tales, -- "There were stern stands And bitter runs for glory."

Ah, I think there were braver deeds.
This is my signature. There are many like it, but this one is mine. My signature is my best friend. It is my life. I must master it as I must master my life. My signature, without me, is useless. Without my signature, I am useless.
Sort of...you''re close.

If the sub-class is defined in the public part of the class, it CAN be accessed from outside the class. However, anybody doing this needs to use the scope-resolution operator like such:
class A{public:  class B  {  };};//now, in some global functionA::B object; // object is a B! 

If the class is defined in the protected section, only that class and derived classes can make an A::B. If in the private, only an A object can have an A::B.
Advertisement
Yes,
To use a real-life example... every STL container needs an iterator class. Rather than having to name each one differently (vector_iterator, list_iterator, ...) they define the iterator class inside the container. That''s why you have to write:

vector<int>::iterator i;

This also has another benefit. If you write your own container, and follow the convention established, you can use it as a drop-in replacement for an STL container, because even the iterators (which are whole other class from the container) are defined via the container itself.

-Brian

This topic is closed to new replies.

Advertisement