Search code examples
c++class-design

Initialising classes inside another class in C++?


I have this definition in a header file:

class Owner
{
private:
    // Fields
    Child* _myChild1;
public:
    // Constructors
    Owner();
    Owner(const char childName[]);
};

and this implementation:

Owner::Owner(const char childName[])
{
//do some operations - children must be created after these ops
_myChild = new Child(childName);
}

and this main() function:

int main()
{
Owner("child1"); 
}

Some questions, and please bear with me here, I'm just starting out with C++ ..

  • Given that the child classes are known at compile time am I right in thinking that I don't need to create them with 'new' on the heap? If so how? I have tried using this syntax in the Owner implementation but the compiler moans ('term does not evaluate to a function..'):

_myChild(childName);

  • However, using this syntax in the implementation is ok, why?

Child _myChild(childName);

  • Is the paradigm that I'm using correct? In other words, as a general rule, if one class wraps another does the owner only ever hold pointers to the classes it wraps?
  • How would you more experienced guys do it?

Thanks for any advice..


Solution

  • Basically, how it works is thus:

    • If the Child class is fully defined before the Owner class, it can be included in the Owner in it's entirety, or as a pointer, whichever you prefer.
    • If the Child class is not fully defined before the Owner class, it would have to be forward declared and can only be included as a pointer. This would have to be allocated on the heap with new.

    If you do include a class in it's entirety, it will be constructed at the same time as the owner object is constructed. Unless explicitly told otherwise, the compiler will use the default constructor for this.

    Option 1:

    // will create a Child object using the default constructor.
    // this is done even before doStuff() is called.
    
    Owner::Owner(const char childName[]) {
      doStuff();
    }
    

    Option 2:

    // will create a Child object using the Child(const char*) constructor.
    // again, done before doStuff() is called.
    Owner::Owner(const char childName[]): _myChild(childName) {
      doStuff()
    }
    

    You can't use the _myChild(childName); syntax inside the constructor itself, since _myChild has already been constructed before it ever gets that far. Child _myChild(childName); is legal, but it creates a new local object named _myChild rather than modifying the class member _myChild. This is probably not the intended result.

    If you want to assign a new value to _myChild after it's constructed, do one the following:

    • Preferred method: Modify the existing object somehow (such as overloading the assignment operator to allow you to do _myChild = childName;, or using some form of _myChild.setName(childName); function).
    • Alternate method: Use _myChild = Child(childName); to create a new Child and assign it to the member variable.

    This second option, although functional, is inefficient since it requires constructing the object twice for no good reason.