multiple inheritance question

Mar 16, 2010 at 3:56pm
Hello,

I would like to have your help about a small problem I am facing right now...

I have the following code:

class alpha
{
public:
alpha() { };
virtual ~alpha() { };

virtual void test();
void access() {test(); }
};

class beta: public alpha
{
public:
beta() { };
virtual ~beta() { };

virtual void test();
};

class gama: public beta
{
public:
gama() { };
~gama() { };

void test() { std::wcout << " I am here!"; }
};

int _tmain(int argc, _TCHAR* argv[])
{
gama t;

t.access();
return 0;
}

I have two classes which inherit a virtual method (test()). A third class also inherits the second from above and defines the virtual method test(). Now when I call access() method from the first class I would like to call the test from the third.

What is wrong with my code?

Thank you very much for your time.

Triantafillos Paradas.
Mar 16, 2010 at 4:17pm
I'm having a similar problem, just I am unable to call access() from my third derived class.

If you split your three classes into a header/cpp file combo and make gama::test() a static function it works, but I'm not sure if that's what you are looking for.

EDIT: Oh, and you have to call it as gama::test() inside alpha, just like you would any static class function.
Last edited on Mar 16, 2010 at 4:19pm
Mar 16, 2010 at 4:25pm
closed account (z05DSL3A)
You have not got a definition for alpha::test() and beta::test().
Either define them
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class alpha
{
public:
alpha() { };
virtual ~alpha() { };

virtual void test(){/*definition*/};
void access()	{test(); }
};

class beta: public alpha
{
public:
beta() { };
virtual ~beta() { };

/*inherits the definition of test() from alpha*/

};


or make it a pure virtual

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class alpha
{
public:
alpha() { };
virtual ~alpha() { };

virtual void test() = 0; /*pure virtual function */
                /*no definition of test so can't instantiate an alpha object*/

void access()	{test(); }
};

class beta: public alpha
{
public:
beta() { };
virtual ~beta() { };

virtual void test(){/*definition*/};

};
Mar 16, 2010 at 4:28pm
First, please use the code tags [ code] and [ /code ]. (You can edit your own post..). This makes it easier to tell you line numbers in your code. ;)

Anyway, I can't spot any conceptional mistake. You have a redundant semi-colon after ~beta and you are missing the implementation of alpha::test and beta::test. But everything else looks fine and works for me, it prints out "I am here!".


Just a blind shot: Maybe it's some silly problem with your console output? Try to output *anything* to make sure your wcout works as expected.. ;)

HarbingTarbl: No, I think he is talking about polymorphism and virtual functions, not about calling functions directly.

Ciao, Imi.
Mar 17, 2010 at 8:51am
THANKS TO ALL for your help.
Now I am facing a different problem and I need your help again. I have:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class alpha
{
public:
	alpha() {}
	alpha(const alpha & rhs)
	{
		test();
	}
	virtual ~alpha() {}

	virtual void test() {}
	void access()	{ test(); }
};

class beta: public alpha
{
public:
	beta() {}
	beta(const beta & rhs):
	alpha(rhs)
	{

	}
	virtual ~beta() {}

	virtual void test() {}
};

class gamma: public beta
{
public:
	gamma() {}
	gamma(const gamma & rhs):
	beta(rhs)
	{

	}
	~gamma(){}

	void test(){std::wcout << " I am here!"; }
};

int _tmain(int argc, _TCHAR* argv[])
{
	gamma	t;
	gamma	f(t);

	t.access();
	f.access();
	return 0;
}


When I create f (line 46) as a copy of t using the copy constructor and this goes down to copy constructor of alpha there the virtual test() is called (line 7). My intention is to call the test() of the gamma class but It looks like the test() of alpha is called. Am I doing something wrong here?

Thanks in advance.
Triantafillos Paradas
Mar 17, 2010 at 9:42am
You are not doing anything "wrong". You just hit a special but heavily discussed "feature" of C++. ;-)

Unlike other OO-languages like Java, in C++, all virtual functions called in the constructor are only resolved until the "current" class. so while you are in a constructor of alpha (including copy constructor), all virtual functions are only resolved until the level of alpha.

The reasoning behind the was, that you should get some kind of guarantee that in a class, every member function is only called after the constructor finished its job (or if its called directly from your own constructor). It was meant to reduce "surprises" when functions suddenly get called without the constructor had a chance to execute first. (Unfortunately its not perfect. There are still some exotic places where these surprises can happen, so in my personal opinion its a wrong decission. But these cases are pretty rare, so maybe the C++ comitee was right after all ;-) ).

Anyway, what this mean is: you can't effectively use virtual functions within a constructor. Sorry.

You could force yourself to always call test() directly after construction. But well.. if you forget... :-(

Or you could provide a function like "clone()" in gamma that will return a copy of itself and then call to test() so you don't forget. And then you use this instead of the copy constructor (and make the copy constructor private):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class gamma {
...
    gamma clone() {}
private:
    gamma(const gamma&) {}
};
...
    gamma t;
    gamma f = clone();
...

gamma gamma::clone()
{
    gamma ret(*this);
    ret.test(); // <-- now gamma::test get called - obviously. It's not even polymorphic anymore
}



If you restrict yourself of creating alpha, beta and gamma objects on the heap using new, the "clone()" can be moved to alpha, made virtual by itself and beta/gamma override it and return a copy of themself on the heap. This is sometimes called "virtual constructor" or "prototype pattern".

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class alpha {
...
    virtual alpha* clone() { alpha x=new alpha(*this); x->test(); return x; }
};

class beta : public alpha {
...
    virtual beta* clone() { beta x=new beta(*this); x->test(); return x; }
};

class gamma : public beta {
...
    virtual gamma* clone() { gamma x=new gamma(*this); x->test(); return x; }
};
...
    gamma t;
    gamma* f = t.clone();
    ...
    f->access();
    ...
    delete f; // don't forget that now, f is on the heap, so you have to fiddle with deleting it.. :( 


(Note, that clone() can return pointer to subclasses and still use virtual overriding. That's a feature of C++. So you don't need to cast to anything when you clone gamma from a gamma object directly. ;)

Within the clone() method, you call the test() after you created a copy of yourself. This pattern is common, but does a lot more than you just have in your example (e.g. you can clone gamma-objects from "pointers to alpha" without even knowing about the class "gamma" or "beta".)


Ciao, Imi.
Mar 17, 2010 at 12:06pm
Imi thank you very much for your time.

I would like to ask you when gamma* f = t.clone(); is executed from your last example I can understand that the copy constructor of gamma is run but I can not figure out how the other objects that gamma inherits from (beta and alpha) are created (which constructor runs).

Thanks.
Mar 17, 2010 at 1:04pm
I can understand that the copy constructor of gamma is run but I can not figure out how the other objects that gamma inherits from (beta and alpha) are created (which constructor runs).


That depends on which constructor do you call for them. If none, the default constructor is used. It's a common mistake to forget to call the base class' copy constructor in a derrived class. Watch out for this. ;-)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct alpha
{
    alpha() {}
    alpha(const alpha& a){}
};

struct beta : alpha
{
    beta() {}
    beta(const beta& b)
    : alpha(b)  // aha! called the copy constructor of alpha. It will be executed before beta's own
    {}
};

struct gamma : beta
{
    gamma() {}
    gamma(const gamma& g)
    // whoops! Didn't call any constructor. beta's default constructor will be used.
    {}
};


Ciao, Imi.
Topic archived. No new replies allowed.