派生类对象是否包含基类对象? [英] Does a derived class object contain a base class object?

查看:174
本文介绍了派生类对象是否包含基类对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下示例代码:

  #include< iostream> 

使用命名空间std;

班级基础
{
public:
base()
{
cout<< 基类中的ctor;
}
};

派生类1:公共基础
{
public:
派生1()
{
cout<<"派生类中的ctor n;
}
};

int main()
{
派生1 d1obj;
返回0;
}

问题


  1. 创建 d1obj 时,将按派生顺序调用构造函数:调用基类构造函数首先是派生类的构造函数。这样做是由于以下原因:为了构造派生类对象,首先需要构造基类对象


  2. d1obj 是否包含基类对象?


我要再添加一个问题



3)创建d1obj时,控件首先到达基类构造函数然后去派生类构造函数?还是相反:它首先到达派生类的构造函数,发现它具有基类,因此控件转到基类中的构造函数?

解决方案

1)是,首先构造基,然后构造非静态数据成员,然后调用派生类的构造函数。原因是此类的构造函数中的代码可以查看和使用完全构造的基数。



2)是。您可以从字面上完全理解:分配给派生类对象的内存中有一个称为基类子对象的区域。派生类对象以与包含任何非静态数据成员的成员子对象完全相同的方式包含基类子对象。但实际上,问题中给出的示例恰好是一种特殊情况:空基类优化。即使基本类型为 base 的完整对象绝不为零,该基类子对象也允许为零。



但是,这种遏制是低级的事情。确实,正如其他人所说,从概念上讲的基础与成员不同,即使子对象本身只是类布局的一部分,语言的语法和语义也将它们区别对待。 / p>

3)这是一个实现细节。基类构造函数主体中的代码先于派生类构造函数主体中的代码执行,实际上,派生类构造函数随后在不可见的编译器生成的try / catch块中执行,以确保是否抛出,基类被破坏。但是,由编译器决定如何根据发出的代码中的函数入口点实际执行的操作来实现此目标。



当类具有虚拟基数时,通常构造函数导致发出两个不同的函数体-一个用于此类是最派生的类型,而另一个用于当此类本身是基类时使用。原因是虚拟基类由派生最多的类构造,以确保在共享它们时仅构造一次。因此,构造函数的第一个版本将调用所有基类构造函数,而第二个版本将仅调用非虚拟基类的构造函数。



编译器始终知道什么该类具有的基数,因为您只能构造一个完整类型的对象,这意味着编译器可以看到该类的定义,并指定了基数。因此,在输入构造函数时,毫无疑问只能发现它具有基类-编译器知道它具有基类,并且对基类构造函数的调用是否位于内部派生类的构造函数代码,这只是为了方便编译器。它可以在构造对象的每个位置向基类构造函数发出调用,对于这种情况,在派生类构造函数可以并内联的情况下,这是最终的效果。


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?

解决方案

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.

这篇关于派生类对象是否包含基类对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆