问题
Having a member and pass the same to the base class works if:
DerrivedClass::DerrivedClass(SomeParamType* p)
: BaseClass(p),
derrivedClassMember(p),
{
...
}
... but how to share without passing it as param to the DerrivedClass constructor? Is this valid? Or is the derrivedClassMember not initialized at this time?
DerrivedClass::DerrivedClass()
: BaseClass(derrivedClassMember),
derrivedClassMember(new SomeParamType()),
{
...
}
I'm not able to change the base class implementation.
回答1:
It is not initialialized at that time. The baseclass constructor is called before the derrivedClassMember is initialized. That's because the derived members or the constructor of the derived class may depend on members of the baseclass.
回答2:
In C++11 you could use a delegating constructor:
class Derived : public Base {
public:
Derived() : Derived(new SomeParamType()) {}
...
private:
Derived(SomeParamType* p) : Base(p), derivedMember(p) {}
};
As a side note, I know this is probably just an example but you shouldn't create unmanaged objects on the heap like this in a constructor: if the Base constructor throws then you're in for a memory leak. Prefer smart pointers whenever possible.
回答3:
I'm cringing as I write this, but....
DerrivedClass::DerrivedClass(SomeParamType* p = new SomeParamType())
: BaseClass(p),
derrivedClassMember(p)
{
}
I need to go shower now. Regardless, in deference to your question, yes, your base constructor should be executed before your members are initialized. Members have to be initialized in their top-down order, starting with the base members in its constructor and working out.
Note: I'd have to dust off my standard copy to find where this is specified, but I'm fairly sure its in there, as lint loves to tell you about out-of-order initialization warnings and their non-compliance.
回答4:
To sum up the answers given up to now, and add a bit more, there are a few possible solutions.
1 If your base class has an accessor for the member, its fairly easy:
DerrivedClass::DerrivedClass()
: BaseClass(new SomeParamType()),
derrivedClassMember(getBaseClassMember()),
{
...
}
2 in C++11, use a delegating constructor, calling the original constructor you posted:
DerrivedClass::DerrivedClass()
: DerrivedClass(new SomeParamType())
{}
3 in C++03, use a default argument (which is ugly):
DerrivedClass::DerrivedClass(SomeParamType* p = new SomeParamType())
: BaseClass(p),
derrivedClassMember(p),
{
...
}
4 Another workaround, to get rid of the constructor default argument in C++03, would be to use multiple inheritance to get the derivedclassMember initialized before the base class:
struct DerivedClassInitializationWorkaround {
SomeParamType* derivedClassMember:
DerivedClassInitializationWorkaround(SomeParamType* param)
: derivedClassMember(param) {}
};
class DerivedClass : private DerivedClassInitializationWorkaround, //this has to go first!
public BaseClass {
public:
DerivedClass::DerivedClass()
: DerivedClassInitializationWorkaround(new SomeParamType())
, BaseClass(derivedClassMember)
{}
};
The initialization of base classes occurs in the order of their declaration, so if you derive from DerivedClassInitializationWorkaround, the derivedClassMember it contains gets initialized first.
In any cases, your code is not exception safe. You should not store owning pointers as raw pointers but use smart pointers. Since you can't change the base class, you will have to determine if it takes ownership of the object (i.e. if it destroys the object you pass to its constructor.
If the base class object takes ownership, you are more or less stuck with the existing solutions, except that your derived class should store a reference instead of the pointer, because the base class object and therfore the SomeParamType object will outlive the derived class' object.
If the base class does not take ownership, you should store a unique_ptr:
class DerivedClass : public BaseClass {
unique_ptr<SomeParamType> derivedClassMember;
DerivedClass::DerivedClass(unique_ptr<SomeParamType> param)
: BaseClass(param.get())
, derivedClassMember(move(param))
{}
public:
DerivedClass::DerivedClass()
: DerivedClass(make_unique<SomeParamType>)
{}
};
回答5:
Short answer is no, it is not valid.
Here's a good answer to your question:
Order of calling base class constructor from derived class initialization list
来源:https://stackoverflow.com/questions/18631784/how-to-remind-a-param-passed-to-the-base-class-constructor