Polymorphic Constructors

Basically, when I create these class's doing this:

1
2
3
CPlayer* List_Players[6];
List_Players[0] = new CDog();
List_Players[1] = new CCar();


the values from the constructors don't work.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//player objects
class CPlayer
{
public:
	string P_Name;
	float P_Money;
	float P_Position;
	float P_number;
	CPlayer();
};

CPlayer::CPlayer(){P_Money = 1500.00;}

//First Player

class CDog : public CPlayer
{
	public:
	string P_Name;
	float P_Money;
	float P_Position;
	float P_number;
	CDog();
};

CDog::CDog()
{
	P_Name = "Dog";
	P_number = 1.0f;
}


How can I get the constructors working in the other class?
Derived classes inherit the parent's members. You don't need to (and you shouldn't) duplicate them.

For example, CPlayer already has P_Name, P_Money, etc, etc. By creating another set of those in CDog, you are creating an entirely different set of variables. In CDog's ctor, you are changing CDog::P_Name, but not CPlayer::P_Name.


To rememdy this... don't dup the variables:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CDog : public CPlayer
{
	public:
/*	string P_Name;  // get rid of all these
	float P_Money;
	float P_Position;
	float P_number;*/
	CDog();
};

CDog::CDog()
{
	P_Name = "Dog";  // now these will change CPlayer::P_Name
	P_number = 1.0f;  //  and CPlayer::P_number as you expect
}
Do they also inherit parents functions?
Barring a few exceptions, yes.
Do you mind naming those exceptions for future reference thanks
- constructors
- destructors
- assignment operator overloads
- functions that have been "hidden":

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A
{
public:
  void foo() { }
};

class B : public A
{
public:
  void foo(int) { }  // this "hides" A::foo
};

int main()
{
  B b;
  b.foo();  // will error because A::foo is hidden
    // to unhide A::foo, put 'using A::foo;' somewhere in B's class definition
}
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?

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?

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

Ok, KEY to my issue is the following: if I do this and separate the new code into a separate class or something--then I loose access to all the stuff I'm trying to inherit. I am starting to wonder if there really is a way to inherit constructors. 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. Maybe doing that isn't such a good idea. If I simply skip that constructor line initialization and write classes the way I used to, it seems like a lot of these problems would go away, or at least I wonder if they would.

Here's an example of why this is a problem for me. Suppose I have a virtual function called from my constructor in my base class. Then, in my new class, I want the same code to be used as in the Base class, but I want it to call the new class's version of the function. I can get it to work by passing functions by void pointers, but that can be a real hassle. Does anyone know what I'm talking about with this problem and have a solution for me? I get the feeling I'm missing something really simple--way too close to it to see the big picture at the moment.
Last edited on
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.
Ok, so we are seeing eye to eye on this. I think you are on to something with the idea of coming up with a new design for what I want to do. My code of the day is basically doing a lot of tedious characterization of vast amounts of data. It involves many many nested loops and whatnot to get to the point where it decides there is a definition of a type of data at a given point. There are too many possible permutations of these characterizations to write them out and deal with them later, so what I want to do is write all the complex code one time, and then let it do different things after it finds a characteristic. I had planned on putting the complex algorithm in a base class and then having inherited classes do other functions at the same places with virtual overrides. Maybe the only problem I'm having is by doing a lot of this through constructor list initialization. It sounds like the right (newly inherited virtual over ride) class functions and or new types of data might be called or accessed from the base class after initialization as long as I keep it all out of the base class constructor. One thing that I have done that works is pass void pointers to the virtual over ride functions as static functions, but the syntax turns into a nightmare that is a bit of a deterrent. Another way for me to imagine solving my problem is something I don't know of existing, but might. If there were a way to write a function that didn't close the lower half of a loop, and then write another function that does close the lower half of a loop, that would be so nice. I've never tried doing something like that, but I do have a recollection of having seen it done--but I never looked into the implementation. That would help me a lot because right now the syntax complexity takes time which then distracts from the bigger picture for writing the complex part of the code that brings me to the places I want to call functions. If I didn't have to close the loops, then I could just make simple calls to represent complex stuff. I don't know if that makes any sense. Do you haven any strategic suggestions for me? Am I making any sense at all? I feel like I'm rambling a bit.
Topic archived. No new replies allowed.