通过私有继承覆盖公共别名方法

时间:2020-06-03 00:12:59

标签: c++ inheritance polymorphism c++17 private-inheritance

我有一个类层次结构,其中有一个基本类型Base和一个实现列表,另一个基本类AnotherBase几乎与Base类似,但有点不同。为了用这种语言表达这一点,我在第二个基类上使用了私有继承(因此,后者的实现与前者之间没有按原样的关系)。

假设这是代码(https://wandbox.org/permlink/2e2EG0eKmcLiyvgt

#include <iostream>

using std::cout;
using std::endl;

class Base {
public:
    virtual ~Base() = default;
    virtual void foo() = 0;
};

class Impl : public Base {
public:
    void foo() {
        cout << "Impl::foo()" << endl;
    }
};

class AnotherBase : private Base {
public:
    using Base::foo;

    // other virtual methods
};

class Derived : public AnotherBase {
public:
    explicit Derived(std::unique_ptr<Base> base) : base_{std::move(base)} {}

    void foo() override {
        base_->foo();
    }

private:
    std::unique_ptr<Base> base_;
};

int main() {
    auto impl = std::make_unique<Impl>();
    std::make_unique<Derived>(std::move(impl))->foo();
}

当我尝试编译以上代码时,出现以下错误

prog.cc:27:38: error: 'Base' is a private member of 'Base'

如果上述方法无效,最好的表达方式是什么?还有为什么它不起作用?

1 个答案:

答案 0 :(得分:5)

Derived声明的这两行中,Base被解析为私有继承的Base类型,因为它在范围内-即使它是私有的:< / p>

explicit Derived(std::unique_ptr<Base> base) : base_{std::move(base)} {}
// ...
std::unique_ptr<Base> base_;

C ++不会忽略范围内的名称,这些名称引用当前作用域无法访问的内容。似乎合乎逻辑的是,编译器将在其可以访问的Base的外部范围内进行查找,但这不会发生。编译器只是停在它看到的最接近的Base上,而不考虑任何访问修饰符。

通过顶级命名空间前缀Base引用::类型,可以轻松解决此问题:

explicit Derived(std::unique_ptr<::Base> base) : base_{std::move(base)} {}
// ...
std::unique_ptr<::Base> base_;

两者都引用相同的类型,但是Derived不能访问继承的Base名称,而它可以访问全局Base名称。

您还可以通过重新定义BaseDerived中的含义来解决此问题。在Derived声明的顶部,您可以添加:

protected:
    using Base = ::Base;

这会将继承的Base名称隐藏在Derived可以访问的类型别名后面。