简体   繁体   English

如何在编译器中实现C ++虚拟继承?

[英]How C++ virtual inheritance is implemented in compilers?

How the compilers implement the virtual inheritance? 编译器如何实现虚拟继承?

In the following code: 在以下代码中:

class A {
  public:
    A(int) {}
};

class B : public virtual A {
  public:
    B() : A(1) {}
};

class C : public B {
  public:
    C() : A(3), B() {}
};

Does a compiler generate two instance of B::ctor function, one without A(1) call, and one with it? 编译器是否生成两个B::ctor函数实例,一个没有A(1)调用,一个带有它? So when B::constructor is called from derived class's constructor the first instance is used, otherwise the second. 因此,当从派生类的构造函数调用B::constructor时,将使用第一个实例,否则使用第二个实例。

The compiler does not create another constructor of B - but it ignores the A(1) . 编译器不会创建另一个B构造函数 - 但它忽略了A(1) Since A is virtually inherited, it is constructed first, with its default constructor. 由于A实际上是继承的,因此首先使用其默认构造函数构造它。 And since it's already constructed when B() is invoked, the A(1) part is ignored. 并且因为它在调用B()时已经构造,所以忽略A(1)部分。

Edit - I missed the A(3) part in C 's constructor initialization list. 编辑 - 我错过了C的构造函数初始化列表中的A(3)部分。 When virtual inheritance is used, only the most derived class initializes the virtual base classes. 使用虚拟继承时,只有最派生的类初始化虚拟基类。 So A will be constructed with A(3) and not its default constructor. 因此A将使用A(3)而不是其默认构造函数构造。 The rest still stands - any initializations of A by an intermediate class (here B ) are ignored. 其余的仍然存在 - 中间类(此处为B )对A的任何初始化都A被忽略。

Edit 2, trying to answer the actual question regarding the implementation of the above: 编辑2,试图回答有关上述实施的实际问题:

In Visual Studio (at least 2010), a flag is used instead of having two implementations of B() . 在Visual Studio中(至少2010年),使用标志而不是B()两个实现。 Since B virtually inherits from A , before it calls A 's constructor, the flag is checked. 由于B实际上继承自A ,因此在调用A的构造函数之前,会检查该标志。 If the flag is not set, the call to A() is skipped. 如果未设置标志,则跳过对A()的调用。 Then, in every class deriving from B , the flag is reset after it initializes A . 然后,在从B派生的每个类中,在初始化A之后重置标志。 The same mechanism is used to prevent C from initializing A if it's part of some D (if D inherits from C , D will initialize A ). 如果它是某些D的一部分,则使用相同的机制来防止C初始化A (如果D继承自CD将初始化A )。

It's implementation-dependent. 它依赖于实现。 GCC (see this question ), for example, will emit two constructors, one with a call to A(1) , another one without. 例如,GCC(请参阅此问题 )将发出两个构造函数,一个调用A(1) ,另一个不调用。

B1()
B2() // no A

When B is constructed, the "full" version is called: 构造B时,调用“完整”版本:

B1():
    A(1)
    B() body

When C is constructed, the base version is called instead: 构造C时,将调用基本版本:

C():
    A(3)
    B2()
       B() body
    C() body

In fact, two constructors will be emitted even if there is no virtual inheritance, and they will be identical. 事实上,即使没有虚拟继承,也会发出两个构造函数,它们将是相同的。

The Itanium C++ ABI is a useful resource for all questions like "how could this be implemented by C++ compilers". Itanium C ++ ABI是所有问题的有用资源,例如“C ++编译器如何实现”。

In particular 5.1.4 Other Special Functions and Entities list different special member functions for different purposes: 特别是5.1.4其他特殊功能和实体列出了用于不同目的的不同特殊成员功能:

 <ctor-dtor-name> ::= C1 # complete object constructor ::= C2 # base object constructor ::= C3 # complete object allocating constructor ::= D0 # deleting destructor ::= D1 # complete object destructor ::= D2 # base object destructor 

The 1.1 Definitions section is useful (but not complete): 1.1定义部分很有用(但不完整):

base object destructor of a class T 类T的基础对象析构函数

A function that runs the destructors for non-static data members of T and non-virtual direct base classes of T. 运行T的非静态数据成员和T的非虚拟直接基类的析构函数的函数。

complete object destructor of a class T T类的完整对象析构函数

A function that, in addition to the actions required of a base object destructor, runs the destructors for the virtual base classes of T. 除了基础对象析构函数所需的操作之外,还运行T的虚拟基类的析构函数的函数。

deleting destructor of a class T 删除类T的析构函数

A function that, in addition to the actions required of a complete object destructor, calls the appropriate deallocation function (ie,. operator delete) for T. 除了完整对象析构函数所需的操作之外,还为T调用适当的释放函数(即,运算符删除)的函数。

From these definitions, the purpose of the complete object constructor and of the base object constructor are obvious. 根据这些定义,完整对象构造函数和基础对象构造函数的目的是显而易见的。

I suggest you to read some papers. 我建议你阅读一些论文。 These two are really interesting, especially the first since it comes from C++'s father: 这两个真的很有趣,特别是第一个来自C ++的父亲:

[1] Bjarne Stroustrup. [1] Bjarne Stroustrup。 Multiple Inheritance for C++. C ++的多重继承。 The C/C++ Users Journal, May 1999. C / C ++用户期刊,1999年5月。

[2] J. Templ. [2] J. Templ。 A Systematic Approach to Multiple Inheritance Implementation. 一种多系统继承实现的系统方法。 ACM SIGPLAN Notices, Volume 28, No. 4 April 1993. ACM SIGPLAN通告,第28卷,1993年4月4日。

I used them as main references while making a seminar (as a student) on multiple inheritance in my university. 我在他的大学进行多重继承的研讨会(作为学生)时,将它们作为主要参考。

As mentioned before, it depends on the compiler implementation. 如前所述,它取决于编译器实现。

But, usually each time a programmer adds a new method, is stored in code, even if there is another method with the same id. 但是,通常每次程序员添加新方法时,都存储在代码中,即使存在具有相同id的另一种方法。 elsewhere ("overriden" or "overloaded"). 其他地方(“覆盖”或“重载”)。

The code for each method is stored only once, so if a class inherits and uses the same method from a parent class, internally, its uses a pointer to the code, it doesn't duplicates the code. 每个方法的代码只存储一次,因此如果一个类从父类继承并使用相同的方法,那么在内部,它使用指向代码的指针,它不会复制代码。

If a parent class defines a virtual method, and if a child class overrides it, both methods are stored. 如果父类定义了虚方法,并且子类覆盖它,则会存储这两种方法。 Each class has something called "Virtual Method Table" where there is a table of pointers to each method. 每个类都有一个名为“虚方法表”的东西,其中有一个指向每个方法的指针表。

Don't worry about performance, the compiler doesn't duplicate code for methods. 不要担心性能,编译器不会为方法重复代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM