简体   繁体   中英

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..

Like this:

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

Owner::Owner()
    :_myChild1("Default Name")
{}

Owner::Owner(const char childName[])
    :_myChild1(childName)
{}

// Without more info about what you are doing it is hard to tell
// But a trivial change could be

Owner::Owner()
// Child defautl constructor called here
{
    // Do processing.
    _myChild1.updateName(name);
}

Owner::Owner(const char childName[])
// Child defautl constructor called here
{
    // Do processing.
    _myChild1.updateName(std::string("X") + childName);
}

The question is what kind of processing do you need done before the child.

As a side not:

  • avoid underscore as the first character in a member name.
    Most of the time it is OK but there are sitations where it is not. So best to just avoid them.
  • Rather than passing an array of characters pass a std::string const&

What you're sort of describing here is "composition", where one class resides in another class. Here, Owner contains a pointer to a Child . So the actually allocation and initialization of the instance of Child must be done somewhere at runtime.

If you want Owner to contain an instance of a Child that you don't have to allocate on the heap with new , simply declare the member variable as:

Child _myChild1;

rather than as a pointer.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM