通过私有继承覆盖公共别名方法
Overriding a publically aliased method via private inheritance
我有一个 class 层次结构,其中有一个带有实现列表的基本类型 Base
和另一个基本类型 class、AnotherBase
,这几乎就像 Base
但有点不同。为了用我在第二个基础 class 上使用私有继承的语言来表达这一点(因此后者与前者的实现之间没有原样关系)。
假设这是代码 (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'
如果这行不通,表达上述想法的最佳方式是什么?还有为什么它不起作用?
在 Derived
声明的这两行中,Base
被解析为私有继承的 Base
类型,因为它在范围内——即使它是私有的:
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
名称。
您还可以通过重新定义 Base
在 Derived
中的含义来解决此问题。在 Derived
声明的顶部,您可以添加:
protected:
using Base = ::Base;
这将继承的 Base
名称隐藏在 Derived
确实可以访问的类型别名后面。
我有一个 class 层次结构,其中有一个带有实现列表的基本类型 Base
和另一个基本类型 class、AnotherBase
,这几乎就像 Base
但有点不同。为了用我在第二个基础 class 上使用私有继承的语言来表达这一点(因此后者与前者的实现之间没有原样关系)。
假设这是代码 (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'
如果这行不通,表达上述想法的最佳方式是什么?还有为什么它不起作用?
在 Derived
声明的这两行中,Base
被解析为私有继承的 Base
类型,因为它在范围内——即使它是私有的:
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
名称。
您还可以通过重新定义 Base
在 Derived
中的含义来解决此问题。在 Derived
声明的顶部,您可以添加:
protected:
using Base = ::Base;
这将继承的 Base
名称隐藏在 Derived
确实可以访问的类型别名后面。