Right, but if you need to pass a new, unique value of one of these variables in the constructor list, I can't get it to let me because they aren't of my class--only of the base class. Is there a way to get it to let me construct those in a new way and still use the Base class's constructor? |
Pass the values onto the base class's ctor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
class Parent
{
int a, b;
public:
Parent(int A, int B) // construct a,b with A,B
: a(A), b(B) { }
};
class Child : public Parent
{
int c;
public:
Child(int A, int B, int C)
: Parent(A,B) // construct parent with A,B
, c(C) // and c with C
{ }
};
|
Another way to put my question is this: If I extend the class a large amount, and need to write a lot of code to initialize the new stuff prior to reusing the Base class constructor, how can that be accomplished? |
You can't.
All base classes are fully constructed
before any child class ctor even begins. If C++ didn't do this, the consequences would be devestating.
To side-step this, you can create an 'Init' function that you use instead of the ctor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
class Parent
{
protected:
void Init();
Parent(bool no_construct) { } // doesn't init itself
public:
Parent() { Init(); } // inits itself
};
class Child : public Parent
{
public:
Child() : Parent(false) // prevent Parent from Initing itself
{
// code here
Init(); // then init the parent
}
};
|
But this design is rather "ew" and should be avoided if possible.
I wonder if I should try to write a separate class for the new stuff and then try to inherit both of them in another class altogether. Hmmm, maybe there is hope, I just have a lot of double-take going on... |
You might be misusing inhertiance if you run into these kinds of problems. Inheritance forms an "is a" relationship. For example:
1 2
|
class Dog { };
class Poodle : public Dog { };
|
Here, Poodle inherits from Dog, implying that a Poodle "is a" Dog. Anything you can do with a Dog you can also do with a Poodle, but you can also do some things with a Poodle that you can't do with other Dogs.
If you build your classes with this design, you generally don't run into the kinds of problems you're having.
What actual classes are you working with here? Maybe you just need to rethink their design?
I just realized it says above directly that constructors are not inherited. This is confusing me a lot because I've recently been making a huge push to use constructor list initialization |
That might have been misleading of me. The parent constructors are still there -- they just can't be used for code constructing child objects.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
class Parent
{
public:
Parent(int) {} // a ctor that takes 1 int
Parent() { }
};
class Child : public Parent
{
public:
Child() : Parent(0) { } // we can call the Parent(int) ctor here just fine
};
int main()
{
Child foo(5); // this would fail, though, because Child has no Child(int) ctor
// ie: it doesn't inherit Parent(int) in the same sense that other functions
// are inherited.
}
|
Suppose I have a virtual function called from my constructor in my base class. |
This is actually a kind of tricky problem. You can't call virtual functions from a Parent class ctor because the child class hasn't been constructed yet (remember: parents are always constructed first). If C++ allowed this it would be devestating. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
class Parent
{
public:
virtual void func() = 0;
Parent()
{
func(); // assuming this calls Child::func (though it's not allowed in C++)
}
};
class Child : public Parent
{
std::string foo;
public:
void func() { foo = "explode"; } // explodes
};
int main()
{
Child explode;
}
|
If the above were allowed, Child::func would be attempting to assign foo before foo was constructed (resulting in heap corruption, possibly access violations and program crashes).
The only real way around this that I know of is the above 'Init' approach, but even that has pitfalls. For example, what if you have another class that derives from Child? Then you have the same problem all over again.