471,122 Members | 848 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,122 software developers and data experts.

Virtual inheritance + copy constructor pitfall

Hi,

Having the following program:

#include <iostream>

struct A
{
A() { std::cout << "A::A()\n"; }
A(const A &) { std::cout << "A::A(const A &)\n"; }
};

struct B: virtual public A
{
B() { std::cout << "B::B()\n"; }
B(const B &b): A(b) { std::cout << "B::B(const B &)\n"; }
};

struct C: public B
{
C() { std::cout << "C::C()\n"; }
C(const C &c): B(c) { std::cout << "C::C(const C &)\n"; }
};

int main()
{
C c;
std::cout << "---\n";
C c2(c);
}

Why does it print:

A::A()
B::B()
C::C()
---
A::A() <--- here
B::B(const B &)
C::C(const C &)

I.e. why is copy constructor for A not called, but default constructor is
called instead?


May 6 '06 #1
3 3602
Marcin Kalicinski wrote:
Hi,

Having the following program:

#include <iostream>

struct A
{
A() { std::cout << "A::A()\n"; }
A(const A &) { std::cout << "A::A(const A &)\n"; }
};

struct B: virtual public A
{
B() { std::cout << "B::B()\n"; }
B(const B &b): A(b) { std::cout << "B::B(const B &)\n"; }
};

struct C: public B
{
C() { std::cout << "C::C()\n"; }
C(const C &c): B(c) { std::cout << "C::C(const C &)\n"; }
};

int main()
{
C c;
std::cout << "---\n";
C c2(c);
}

Why does it print:

A::A()
B::B()
C::C()
---
A::A() <--- here
B::B(const B &)
C::C(const C &)

I.e. why is copy constructor for A not called, but default constructor is
called instead?

You didn't initialise A in C's copy constructor.

Try

(const C &c): B(c), A(c) { std::cout << "C::C(const C &)\n"; }

--
Ian Collins.
May 6 '06 #2
* Marcin Kalicinski:
Hi,

Having the following program:

#include <iostream>

struct A
{
A() { std::cout << "A::A()\n"; }
A(const A &) { std::cout << "A::A(const A &)\n"; }
};

struct B: virtual public A
{
B() { std::cout << "B::B()\n"; }
B(const B &b): A(b) { std::cout << "B::B(const B &)\n"; }
};

struct C: public B
{
C() { std::cout << "C::C()\n"; }
C(const C &c): B(c) { std::cout << "C::C(const C &)\n"; }
};

int main()
{
C c;
std::cout << "---\n";
C c2(c);
}

Why does it print:

A::A()
B::B()
C::C()
---
A::A() <--- here
B::B(const B &)
C::C(const C &)

I.e. why is copy constructor for A not called, but default constructor is
called instead?


Constructors of virtual base classes have to be called (implicitly, or
explicitly via constructor initializer list) in the most derived class.

Otherwise, in the context of multiple inheritance, where the virtual
base class object is shared between two or more derived class objects,
you could get multiple calls of constructors on the same virtual base
class object, and the ordinary rules for C++ guarantee exactly one
constructor call per object (unless you do Dirty Things).

So your call in B is simply ignored*.
*) This is specified by 12.6.2/6, "a mem-initializer naming a virtual
base class shall be ignored during execution of the constructor of any
class that is not the most derived class."

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
May 6 '06 #3
Marcin Kalicinski wrote:
Hi,

Having the following program:

#include <iostream>

struct A
{
A() { std::cout << "A::A()\n"; }
A(const A &) { std::cout << "A::A(const A &)\n"; }
};

struct B: virtual public A
{
B() { std::cout << "B::B()\n"; }
B(const B &b): A(b) { std::cout << "B::B(const B &)\n"; }
};

struct C: public B
{
C() { std::cout << "C::C()\n"; }
C(const C &c): B(c) { std::cout << "C::C(const C &)\n"; }
};

int main()
{
C c;
std::cout << "---\n";
C c2(c);
}

Why does it print:

A::A()
B::B()
C::C()
---
A::A() <--- here
B::B(const B &)
C::C(const C &)

I.e. why is copy constructor for A not called, but default constructor is
called instead? From Stroustrup's The C++ Programming Language:


"[...] the language ensures that a constructor for a virtual base is
called exactly once. The constructor of a virtual base is invoked
(implictly or explicitly) from the constructor for the complete object
(the constructor for the most derived class)."

That means C is in charge of calling not only B's constructor, but A's
also. Make it:

struct C : public B
{
C(const C &c)
: B(c), A(c)
{
}
};
Jonathan

May 6 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by lok | last post: by
14 posts views Thread by Bruno van Dooren | last post: by
3 posts views Thread by lhr_cool_guy | last post: by
3 posts views Thread by Klaas Vantournhout | last post: by
2 posts views Thread by Henrik Goldman | last post: by
12 posts views Thread by Massimo | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.