c++ - 为什么 C++11 中的统一初始化在虚拟基类中表现得很奇怪?

标签 c++ c++11 inheritance multiple-inheritance virtual-inheritance

现在,我正在学习 C++ 中的继承功能,并想测试最近学习的虚拟基类的概念。 我尝试了以下简单代码:

#include <iostream>

using namespace std;

class A
{
private:
    int m_value;
    string m_caller;
public:
    A(int p_value, string p_caller) : m_value{p_value}, m_caller{p_caller}
    {
        cout<<"Instantiating A via "<<m_caller<<endl;
    }
};

class B : virtual public A
{
private:
    int m_value;
public:
    B(int p_value1,int p_value2) : A{p_value1,"B"}, m_value{p_value2}
    {
        cout<<"Instantiating B."<<endl;
    }
};

class C : public B
{
public:
    C(int p_value1,int p_value2) : A{p_value1,"C"}, B(p_value1, p_value2)
    {
        cout<<"Instantiating C."<<endl;
    }
};

int main()
{
    C c1(1,2);
    return 0;
}

请注意 C 类的构造函数中的 B(p_value1, p_value2)。这给了我想要的输出:

Instantiating A via C
Instantiating B.
Instantiating C.

但是,当我将其更改为 B{p_value1, p_value2} 的那一刻,我得到了以下输出:

Instantiating A via C
Instantiating A via B
Instantiating B.
Instantiating C.

我试图寻找答案,但我得到的所有答案都引用了一些 C++ 标准。作为 OOP 的初学者,我正在为这种行为寻找更简单的解释。 非常感谢!

附:我在带有编译器 g++ 4.8.1 的 Windows 中使用 C::B。

最佳答案

这是 g++ 中的编译器错误。

在 C++14 (N4140) 部分 [dcl.init.list] 中,列表初始化的定义为(为简洁而编辑):

List-initialization of an object or reference of type T is defined as follows:

  • If T is an aggregate, aggregate initialization is performed
  • Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
  • Otherwise, if T is a specialization of std::initializer_list, [...]
  • Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution. If a narrowing conversion is required to convert any of the arguments, the program is ill-formed.
  • [...]

前 3 点不适用:B 不是聚合(聚合不能有基类),初始化列表确实有元素,B 不是std::initializer_list 的特化。

第四点确实适用,因为重载解析根据 [over.match.list] 将 B{p_value1, p_value2} 与构造函数 B(int, int) 匹配/1.2:

If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.

从最后的引用中可以看出,B(whatever)B{whatever} 的行为应该相同。

关于c++ - 为什么 C++11 中的统一初始化在虚拟基类中表现得很奇怪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38061779/

相关文章:

c++ - 不同的编译结果 : Mac vs Windows

c++程序在运行时停止工作

c++ - c++中是否有任何内置功能可以在预定时间运行任务

c++11 - 迭代时不打印变量

c++ - visual studio 2008 探查器是否与非托管 C++ 一起工作?

c++ - 使用基于模板类类型的单独函数

c++11 - 具有模板化返回类型的虚拟成员函数的实例化

c++ - 如何使用来自不同继承层次级别的多个虚函数指针作为模板参数?

java - 扩展类和静态变量

c++ - 重载运算符+