Virtual inheritance and constructors

Jan 8, 2010 at 12:54am
I've been programming "C in C++" for around 10 years, mainly using classes for religious data encapsulation, and have been mucking around with virtual functions recently, trying to replicate the *effect* of function pointers in C.

I've reviewed the forums and can't find anyone dealing with this permutation of my problem.

Consider this code:

class A {
public:
	virtual void f() { printf("Base\n"); }	;
};

class B: public virtual A {
public:
	void f() { printf("f1\n"); };
	B() { printf("B\n"); };
};


class C: public virtual A, public virtual B {
public:
	void f() { printf("f2\n"); };
	C() { printf("C\n"); };
	};

int main(int argc, char* argv[]) {
	
	A *a1, *a2;
	B *b = new B();
	C *c = new C();

	
	a1 = b;
	a2 = c;
	
	a1->f();
	a2->f();
	}


Basically B is built from A, and C is built from A and B. Virtual inheritance. I get what I want, which is for f() calls derived from A that are present in B and C to be local in scope.

But. Let's comment out the stuff in Main, and change the constructor in B to say B(short x) {}; and you will get a compiler error that no matching functions were found:

No matching function for call to B::B()
Candidates are B::B(short int)
B::B(const B&)


And this is on the line for the constructor for C!
	C(short x) { printf("C\n"); };


But. If you make the corresponding changes to C, instead (C short x), no compiler error.

But. If you make the corresponding changes to both functions, compiler error (again at the C constructor definition).

Seriously confused. How do I use non-trivial constructors in B and C? If at all?




Jan 8, 2010 at 1:02am
C's constructor is calling B's constructor. Since you defined a constructor yourself, the default one is no longer available. If you don't tell C's constructor which constructor to call, it'll try calling one that takes no parameters, which now no longer exists.
You can do this:
C():B(etc){}
Jan 8, 2010 at 2:06am
Thanks helios, but I think (first mistake?) that's the opposite of my situation.

If I define a constructor for C, no errors, all is well.
C(short a) { printf("C\n"); };


If I also define a constructor for B, I get the same error as above, that C is looking for a B::B().

B(short a, short b) { printf("B\n"); };


In that case, both classes would appear to me to have valid constructors and if I'm reading you correctly, the task would then be to force the classes to actually use them. How would I do that?

The compiler is gcc 4.2, C GNU99, FWIW.
Jan 8, 2010 at 2:52am
Just to make sure you know... the "default ctor" is the ctor that can be called with no parameters. The compiler will automatically generate one for your class unless you define your own constructor. Therefore:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

// A has a default ctor (automatically generated)
class A
{
};

// B does not have a default ctor
//  because it defines its own ctor
class B
{
public
  B(int v) { }
};

// C does have a default ctor
class C
{
public:
  C(int v) { }
  C() { /* This is the default ctor */ }
};


If I define a constructor for C, no errors, all is well.


This is because C's default ctor is never called. Therefore there's no reason for error.

If I also define a constructor for B, I get the same error as above, that C is looking for a B::B().


Right.. because C's contructor is implicitly calling B's default constructor -- and you no longer have a default constructor.

It's not whether or not your constructors are valid... it's about whether or not you're calling a constructor that exists.

If you don't explictly choose a constructor for your parents, then it will implicitly use the default constructor. That's what happening with you... the error comes from the fact that you no longer have a default constructor, and therefore it's trying to call a ctor that doesn't exist.

The solution here is to either:

1) give B a default ctor

1
2
3
4
5
6
class B: public virtual A {
public:
	void f() { printf("f1\n"); }
        B(short int) { }
	B() { }  // make sure you have a default ctor
};


or

2) explicitly call a different ctor for B from C's ctor:

1
2
3
4
5
6
7
8
class C: public virtual A, public virtual B {
public:
	void f() { printf("f2\n"); }
	C()
	  : B(5)  // explicitly call B's ctor
	{ }
 
	};

Last edited on Jan 8, 2010 at 2:52am
Jan 8, 2010 at 3:23am
OK, I think I get it now. Thanks for your time!
Feb 3, 2010 at 10:22am
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
#include <iostream.h>

class A {
    protected:
    int a,b;

    public:
    A(int x, int y)
    {
        a=x; b=y;
        cout << "A";
    }

};

class B :virtual public A {

    protected:
    int c;

    public:
    B(int x, int y,int z) : A(x,y),c(z)
    {}

};


class C : public B  {

    protected:
    int d;

    public:
    C(int x,int y,int z,int w) : B(x,y,z),d(w)
    {}
};

main()
{
    C c(1,2,3,4);
}



In constructor `C::C(int, int, int, int)':
no matching function for call to `A::A()'
A::A(const A&)
A::A(int, int)


i have similar problem
i know, that without virtual(class B :virtual public A ) it works, but i need class B for multiple inheritance.

Thanks
Feb 3, 2010 at 1:23pm
I think there have been some details left out in the answer.

Read here:
http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.12

Topic archived. No new replies allowed.