在父类中公开受保护的构造函数

YiF*_*Fei 7 c++ inheritance encapsulation language-lawyer

正如标题所说,我想知道是否有一种方法可以在派生类中公开受保护的构造函数(即,将访问权限从 更改protectedpublic)。考虑以下(人为的)示例:

struct A {
    int a;
    int b;
protected:
    A(int, int) {};
    void do_something();
};

struct B : A {
    B() : A(0, 0) {};
    using A::A;
    using A::do_something;
};

int main() {
    B b(0, 0); // error: 'A::A(int, int)' is protected
    //B b{}; // no errors
    b.do_something();
}
Run Code Online (Sandbox Code Playgroud)

那么可以更改受保护成员函数的访问权限,但不能更改构造函数的访问权限吗?如果是这样,限制的理由是什么?


变通方法:带有参数转发的可变参数模板可以作为一种执行相同的变通方法。


推测基本原理:默认情况下,基类的构造函数不是常规意义上的“继承”;派生类的构造函数必须首先构造基类实例。当using用于常规成员函数时,它将函数引入当前声明区域从而改变访问;在构造函数上,using只将基本构造函数带到“正常继承”级别(与没有 的其他成员函数相同using)。因为只有在某些情况下构造函数继承(基构造函数的重用)才有用,标准委员会的人指定using X::X了构造函数继承的语法,而不是更强的命名空间传送。

crs*_*rsn 1

您想要做的是使用两个参数调用构造函数 B,但它不接受任何参数。

你得到的错误是关于 B 的构造函数被保护的,但如果你仔细看,那不是你声明的构造函数:

error: 'B::B(int, int)' is protected
Run Code Online (Sandbox Code Playgroud)

这是为什么?因为编译器正在尝试将您的调用解析为有效的内容,并且它会找到与签名匹配的基类构造函数。但它仍然受到保护,所以失败了。

为了将受保护的构造函数“重新启动”到继承的类,您需要做的是提供一个匹配的构造函数:

struct B : A {
    B() : A(0, 0) {};
    B(int a, int b) : A(a, b) {};
    using A::A;
    using A::do_something;
};

int main() {
    B b;
    B b2(1, 2);
    //b.do_something();
}
Run Code Online (Sandbox Code Playgroud)

http://cpp.sh/9tvik

之所以不能像更改方法的访问器级别一样更改构造函数的访问器级别,很可能是为了探究构造函数的非虚拟性质。[需要引用:)]

  • 该修复有效,但问题是,*为什么*在这种情况下常规成员函数和构造函数之间存在差异。 (2认同)