Does a derived class object contain a base class o

2019-02-15 22:35发布

Consider the following sample code below:

#include <iostream>

using namespace std;

class base
{
   public:
      base()
      {
         cout << "ctor in base class\n";
      }
};

class derived1 : public base
{
   public:
      derived1()
      {
         cout <<"ctor in derived class\n";
      }
};

int main()
{
   derived1 d1obj;
   return 0;
}

Questions

  1. When d1obj is created, the constructors are invoked in the order of derivation : base class constructor is called first and then the derived class constructor. Is this done because of the following reason : In-order to construct the derived class object the base class object needs to be constructed first?

  2. Does d1obj contains a base class object ?

I am adding one more question

3) When d1obj is created, the control first reaches the base class constructor and then it goes to the derived class constructor? Or is it the other way round : It first reaches the derived class constructor, finds that it has base class and so the control goes to the constructor in base class?

5条回答
太酷不给撩
2楼-- · 2019-02-15 23:17

1-- Yes. And it is logical that way.

Objects of type derived1 are special objects of type base, which means that, as a first thing, they are objects of type base. This is what is constructed first, then "derived1" adds its "specialty" to the object.

2-- It is not a question of containing, it is inheritance. See my paragraph above to better understand this answer.

查看更多
地球回转人心会变
3楼-- · 2019-02-15 23:22
  1. Yes

  2. Well, conceptually, not really. d1obj contains all of the data members that an instance of base would, and responds to all of the member functions that said instance would, but does not "contain" an instance of base: you cannot say d1obj.base.func() for instance. If you have, say, overloaded a method your parent declared, you can, however, call d1obj.base::func() to get its implementation, rather than just calling d1obj->func().

While it may seem a little like splitting hairs to say that you contain all of the data and methods of your parent without conceptually containing an instance of your parent, this is an important distinction, as you can often attain many of the benefits of direct inheritance by creating a class which contains the "parent" class as member data, like so:

class derived2 /*no parent listed */ {
public:

   derived2() :_b() {}

private:
    base _b;
}

Such a construct allows you to make use of methods already implemented by base, as implementation details of your own methods, without having to expose any methods which base declared public but that you don't want to grant access to. An important example of this is stack, which can contain an instance of another STL container (such as vector, deque or list), then use their back() to implement top(), push_back() for push() and pop_back() for pop(), all without having to expose the original methods to the user.

查看更多
何必那么认真
4楼-- · 2019-02-15 23:34
  1. Yes. Imagine that in the constructor of the derived class, you want to use some members of the base class. Therefore, they need to be initialized. So it makes sense for the base class constructor to be called first.

  2. d1obj is a base class object. That's what inheritance is. In a way you could say it contains an object of the base class. In memory, the first part of the object will correspond to a base object (in your example you have no virtual functions, if you did, you'd have a pointer to the vftable of derived1 first, then your base class members) and after that the members belonging to derived1.

查看更多
欢心
5楼-- · 2019-02-15 23:37

Yes, and yes.


Since your edit, ad 3) The derived class constructor calls the base class constructor as its first act of duty; then all the member object constructors, and finally it executes the constructor body.

Destruction works the opposite way: First the destructor body executes, then the member objects are destroyed (in reverse order of their destruction), and finally the base subobject destructor is called (which is why you always need an accessible destructor in the base class, even if it is pure-virtual).

查看更多
劳资没心,怎么记你
6楼-- · 2019-02-15 23:40

1) Yes, bases are constructed first, then non-static data members, then the constructor of the derived class is called. The reason is so that the code in the constructor of this class can see and use a fully-constructed base.

2) Yes. You can take this entirely literally: within the memory assigned to the derived class object, there is a region called the "base class sub-object". A derived class object "contains" a base class subobject in precisely the same way that it contains member subobjects for any non-static data members. Actually though, the example given in the question happens to be a special case: the "empty base class optimization". This base class subobject is permitted to be size zero, even though complete objects of type base are never size zero.

This containment is a low-level thing, though. It's true as others say that conceptually bases are different from members, and the syntax and semantics of the language treat them differently even though the sub-objects themselves are all just parts of the layout of the class.

3) This is an implementation detail. The code in the body of the base class constructor is executed before the code in the body of the derived class constructor, and in effect the derived class constructor is then executed in an invisible compiler-generated try/catch block to ensure that if it throws, the base class is destructed. But it's up to the compiler how to achieve this in terms of what the function entry points in the emitted code actually do.

When a class has virtual bases it's common for a constructor to result in two different function bodies being emitted - one for use when this class is the most derived type, and one for use when this class is itself a base class. The reason is that virtual base classes are constructed by the most-derived class, to ensure that when they're shared they're only constructed once. So the first version of the constructor will call all base class constructors, whereas the second version will only call constructors for non-virtual bases.

The compiler always "knows" what bases the class has, because you can only construct an object of a complete type, which implies the compiler can see the class definition, and that specifies the bases. So there's no question of only "finding that it has a base class" when the constructor is entered - the compiler knows that it has a base class, and if the call to the base class constructor is located inside the derived class constructor code, that's just for the convenience of the compiler. It could emit the calls to the base class constructors at every place you construct an object, and for that matter in cases where the derived class constructor can be and is inlined, that's the final effect.

查看更多
登录 后发表回答