c++ inheritance and constructors
class A {
public:
A(int i): data(i) {cout << "A::A(" << i << ")" << endl;}
A(const char* s): data(0) { cout << "A::A(" << s << ")"<< endl;}
~A() { cout << "A::~A()" << endl;}
private:
int data;
};
class B:public A {
public:
B(const A& a): A(a){ std::cout << "B::B开发者_高级运维(const A& a)" << std::endl;}
~B() { std::cout << "B::~B()" << std::endl;}
};
int main() {
B b0(0);
B b1("abc");
return 0;
}
Pretty straightforward, can someone explain why the output is :
A::A(0)
B::B(const A& a)
A::~A()
A::A(abc)
B::B(const A& a)
A::~A()
B::~B()
A::~A()
B::~B()
A::~A()
B b0(0);
- there's no such constructor for B, so the compiler is looking for some constructor, that can be called with just one cast (one implicit cast is allowed, 2 are not), so it finds B::B(const A& a)
, because A
has a constructor with only one parameter, and this is A::A(int i)
. This means, that 0 can be casted to int
, so temporary A
object is created (and destroyed, after B is created). So, here's why we have
A::A(0)
B::B(const A& a)
A::~A()
Then the next is called: B b1("abc");
, so here comes:
A::A(abc)
B::B(const A& a)
A::~A()
This is absolutely the same as with int
, but here with char*
.
Then, both objects are destructed, so their destructors are called in the opposite order, as their constructors are called, that's where
B::~B()
A::~A()
B::~B()
A::~A()
comes from.
It looks confising, because you haven't overloaded A::A( const A& a)
and you don't see, that it is called 2 times, too.
Cheers (:
A small edit: not A::A()
, but A::A( const A& a)
- thanks to Nim.
You don't have a default constructor for B
, so the compiler finds the best alternatives (i.e. construct A
first with the matching inputs and then construct B
from that.)
sequence would be:
- construct temporary
A
withint
- construct
B
with thisA
- destroy that
A
- (you don't have a copy constructor for
A
, else you'd see that thrown in there too!) - same for string
- then sequence of base class/derived class destructors.
A temporary A
object is constructed, then passed via a const reference to B
's constructor, where it is copied using the copy ctor (which you haven't augmented with debug output, so you can't see it) into the B
object.
Destruction takes place in reverse order of construction; the temporaries are destroyed when the constructor which they were passed to is finished.
It constructs a temporary A with the argument in the B constructor which it uses to initialise B::A (via the default copy constructor - hence no output for A::A(const A&)) The temporary A is destroyed after the call to B::B is complete.
1. A::A(0) <- temporary A in B b0(0) line
2. B::B(const A& a) <- construct b0, no visible call to A as you did not provide A(A const &)
3. A::~A() <- destroy temporary A created in line 1
4. A::A(abc) <- temporary A in B b1("abc") line
5. B::B(const A& a) <- construct b1, no visible call to A as you did not provide A(A const &)
6. A::~A() <- destroy temporary A created in line 4
7. B::~B() <- b1 ~B() destructor
8. A::~A() <- b1 ~A() destructor
9. B::~B() <- b0 ~B() destructor
10. A::~A() <- b0 ~A() destructor
I'll try:
A::A(0) // 1: construct an A using A(int) ctor in line 1 of main
B::B(const A& a) // 2: construct a B passing the previously constructed A by const ref
A::~A() // 3: destruct the temporary A made in 1
A::A(abc) // 4: construct an A using A(const char*) ctor in line 2 of main
B::B(const A& a) // 5: construct a B passing the previously constructed A by const ref
A::~A() // 6: destruct the temporary A made in 4
// unwind the stack on exit of main
B::~B() // destruct B made in main line 2
A::~A() // destruct A inherited by B made in main line 2
B::~B() // destruct B made in main line 1
A::~A() // destruct A inherited by B made in main line 1
精彩评论