【问题标题】:Is an inherited default constructor also user-defined?继承的默认构造函数也是用户定义的吗?
【发布时间】:2013-05-22 18:13:36
【问题描述】:

Clang documentation 巧妙地解释了这一点

如果类或结构没有用户定义的默认构造函数,C++ 不允许您默认构造它的 const 实例,例如 这([dcl.init],p9)

下面的代码有这样一个用户定义的Base的默认构造函数,但是g++和Clang不同意Derived的默认构造函数是否是用户定义的,即使Derived确实显式继承了所有@987654326 @构造函数(使用new C++11 inheriting constructors feature

#include <iostream>

class Base
{
public:
    Base(): b_(0) {}  // look! user-defined default constructor
    void print() const { std::cout << b_ << "\n"; }
private:
    int b_;
};

class Derived
:
    public Base
{
    using Base::Base; // does this constitute a user-defined default constructor?
};

int main()
{
    Base const b;
    b.print();    // 0 for g++ & CLang

    Derived const d;
    d.print();    // 0 for g++, Clang: "default initialization of an object of const type 'const Derived' requires a user-provided default constructor"
}

g++ 4.8 很乐意接受此代码,但 Clang 3.3 不接受。标准是怎么说的?

注意:没有Base 的用户定义默认构造函数,g++ 4.8 和 Clang 3.3 都不接受 Base const b;(而例如 g++ 4.7.2 之前接受了)。鉴于 g++ 知道该规则,我认为这意味着 g++ 将 Derived 的默认构造函数视为用户定义的。但 Clang 3.3 不这么认为。

更新:基于@JesseGood 的回答,即0/1 参数构造函数永远不会被继承,我尝试将Base 构造函数更改为

Base(int b = 0, void* = nullptr): b_(b) {}

但它不能解决 Clang 错误。

【问题讨论】:

  • 你说得对,我误读了这个问题。

标签: c++ c++11 g++ clang default-constructor


【解决方案1】:

Clang 是正确的。

关于 const 实例的相关文章来自 8.5p7:

如果一个程序调用一个对象的默认初始化 const 限定类型 T,T 应为具有 用户提供 的类类型 默认构造函数。

由于Base(): b_(0) {} 是用户提供的,所以Base const b; 没问题。

下一个重要的部分是 12.9p3:

对于继承的候选集中的每个非模板构造函数 构造函数除了没有参数的构造函数或 具有单个参数的复制/移动构造函数,构造函数是 隐式声明具有相同的构造函数特征,除非 有一个用户声明的具有相同签名的构造函数 使用声明出现的类

这里的重要部分是粗体文本。我相信这排除了你的情况,因为Base() 是一个没有参数的构造函数。这意味着Derived 没有用户提供的默认构造函数(尽管仍然隐式声明了一个)。

这也意味着来自基类的默认、复制和移动构造函数从不继承。

【讨论】:

  • +1 感谢您的回答。如果我将Base 构造函数签名更改为Base(int b = 0, void* = nullptr): b_(b) {},默认构造函数将被抑制。但是 Clang 仍然在 Derived 上给出错误(并且 g++ 接受它)。带有2个默认参数的构造函数是否也算作不带参数的非继承构造函数?
  • @rhalbersma:是的,它仍然算作没有参数的非继承 ctor。 Base(int)Base(int, void*) 是继承的。 (但是,不继承默认参数)。
  • 如果我正确理解 12.9p3 部分,正确的解释(对于 C++11)将是完全忽略 using Base::Base,因为唯一可以继承的构造函数没有参数,所以它不是。所以即使没有 const 资格,它也行不通。奇怪的是,文本标准没有说明为什么默认结构在遗产中受到歧视。此外,似乎该子句已被删除,因为:类继承构造函数并声明一个(因此没有隐式默认值)无法使用 g++-4.8 编译无参数声明,但适用于 g++-7.3
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-20
  • 2016-03-24
  • 1970-01-01
  • 2017-10-04
  • 2015-07-09
  • 1970-01-01
  • 2013-06-01
相关资源
最近更新 更多