【问题标题】:Inheriting constructors w / wo their default arguments?继承构造函数w / wo他们的默认参数?
【发布时间】:2015-10-28 03:03:06
【问题描述】:

C++ Primer(第 5 版)第 629 页指出:

  • 如果基类构造函数具有默认参数,则不会继承这些参数。

我自己尝试过,对我来说,编译器生成的派生构造函数似乎也具有与基本构造函数相同的默认参数。

这里有一个小测试:

#include <iostream>

struct Base
{
    Base() = default;

    Base(int x_, int y_ = 88, int z_ = 99)
        : x(x_), y(y_), z(z_) {}

    virtual void debug() const 
    { std::cout << "\nx - " << x << ", y - " << y << ", z - " << z << '\n'; } 

private:
    int x, y, z;
};

struct Derived : Base
{
    using Base::Base;
};

int main() {
    Base B(1);
    B.debug();         // x - 1, y - 88, z - 99
    Derived D(5);
    D.debug();         // x - 5, y - 88, z - 99

    return 0;
}

(您可以在此处运行 - http://coliru.stacked-crooked.com/a/26cbb85757c1f021


那么我们是否也继承了被继承构造函数的默认参数?
如果不是,为什么我没有得到最后 2 个成员的垃圾,而是与从 base 继承的构造函数的默认参数完全相同的值?
也在互联网上搜索了关于此的明确回复,但没有找到。

【问题讨论】:

    标签: c++ c++11 inheritance constructor default-arguments


    【解决方案1】:

    您对本书的引用不完整。

    如果基类构造函数具有默认参数(第 6.5.1 节,第 236 页),则这些参数 不被继承。相反,派生类在 其中每个带有默认参数的参数都被依次省略。例如,如果 基类有一个带有两个参数的构造函数,其中第二个有默认值, 派生类将获得两个构造函数:一个具有两个参数(并且没有 默认参数)和第二个构造函数,其单个参数对应于 基类中最左边的非默认参数

    所以你的 Derived 类将有 3 个带有签名的继承构造函数:

    Derived (int x): Base{x} {}
    Derived (int x, int y): Base{x, y} {}
    Derived (int x, int y, int z): Base{x, y, z} {}
    

    所以你没有从基类继承任何默认参数。

    Derived D(5);
    

    调用上述三个构造函数中的第一个,然后调用基构造函数

    Base(5)
    

    还要注意默认、复制和移动构造函数不是 遗传。这些构造函数是使用常规规则合成的。继承的 构造函数不被视为用户定义的构造函数。因此,一个类 只包含继承的构造函数会有一个合成的默认构造函数。

    【讨论】:

    • 这对我的问题没有任何影响。
    • 太棒了!没这么看。谢谢!但是为什么如果 Derived D(5) 调用 Base(5),当我打印 D 的成员时,我得到 5、88、99?最后 2 个成员不应该保持未初始化吗?
    • 因为基本默认参数没有消失。他们还在那里。而 Base(5) 真正调用 Base(5, 88, 99)
    【解决方案2】:

    来自 [class.inhctor]:

    从使用声明中命名的类 X 继承的候选构造函数集包括实际的 由默认参数的转换产生的构造函数和名义构造函数和 省略号参数规格如下:
    — [...]
    — 对于 X 的每个具有至少一个带默认参数的参数的非模板构造函数,集合 由于省略任何省略号参数规范和连续省略而产生的构造函数 参数类型列表末尾带有默认参数的参数,以及
    — [...]

    我们有两个Base 的非模板构造函数。 Base的默认构造函数引入了候选:

    Derived() : Base() { }
    

    Base 的另一个构造函数为每个连续省略的参数引入一个候选者。即:

    Derived(int x, int y, int z) : Base(x, y, z) { }
    Derived(int x, int y)        : Base(x, y) { }
    Derived(int x)               : Base(x) { }
    

    默认参数是继承的 - 我们只是为每个参数数量获得不同的构造函数。所以Derived(5) 只是调用Base(5),而不是Base(5, 88, 99)

    最终结果是一样的——只是我们到达那里的方式有点不同。

    【讨论】:

    • 好的,但是为什么如果“ Derived(5) 只是调用 Base(5),而不是 Base(5, 88, 99)。”当我打印 D 的成员时,我得到 5、88、99?最后 2 个成员不应该未初始化吗?
    • @Mugurel 因为Base(5) 调用Base(int x_, int y_ = 88, int z_ = 99)Derived 没有默认参数,但 Base 仍然有。
    • “最终结果是一样的——只是我们到达那里的方式有点不同。”噗 :-)))) 谢谢!
    • 值得注意的是,委员会可能会通过N4429(或该论文的修订版)对继承构造函数进行重大修改,并作为针对 C++11 的 DR。
    猜你喜欢
    • 2016-03-24
    • 2011-05-20
    • 2015-10-18
    • 2017-10-04
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-18
    相关资源
    最近更新 更多