【问题标题】:Can't friend a class that virtual inherits from it in C++不能在 C++ 中与虚拟继承的类成为朋友
【发布时间】:2016-12-25 15:27:48
【问题描述】:

我想让它只有一个类 Der 可以子类化 Base 类。所以我将Base的构造函数设为私有,并将Der添加为Base的好友:

struct Base {
 template<class T>
 friend struct Der;
 private:
  Base() = default;
};

template<class T>
struct Der : Base {};

这很好用。

然而,另一个结构 DerDer 继承自 Der,多次使用不同的模板参数。

struct DerDer : Der<int>, Der<char> {};

这是一个问题,因为现在层次结构中有两个Base,所以解决方法是让Der虚拟继承自Base

template<class T>
struct Der : virtual Base {};

这现在打破了,我相信如果一个类实际上是继承的,那么最派生的类负责调用构造函数(不确定为什么)。这是一个问题,因为DerDer 不是 Base 的朋友,因此无法访问它的构造函数。

我该如何解决这个问题?

(看起来这是一个实现细节,虚拟继承使最派生的类调用构造函数,因此交友应该尊重这样做是正确的,这是编译器(或标准)中的一种错误)

【问题讨论】:

  • 不,它不是最派生类调用Base的构造函数的实现细节。我相信它是在标准中指定的。遇到您的问题,最简单的解决方法是使 Base::Base() 成为 public 成员函数。
  • 另一种选择是使用合成。请参阅此常见问题以确认它是标准以及为何如此:isocpp.org/wiki/faq/…
  • @RSahu,我知道它在标准中,这就是为什么我说它“看起来像”,因为它只是出于必要(原因我还不明白)。鉴于调用基类的构造函数的最派生类是规范的例外,因此产生一个允许最派生类能够调用虚拟继承类的私有构造函数的并行异常似乎是合理的。 (这不会是一个统一的规则,但它会保持统一的行为)
  • @Jonathan。考虑一下。如果你从两个类继承,这两个类都从 Base 虚拟继承。而且您还希望将 Base 构造函数的调用委托给它们中的任何一个。你会选择哪一个?在这种情况下,你怎么能确定它只被调用一次(使用虚拟继承的原因),因为它们可以有自己的层次结构,而另一个类也继承自 Base,也是虚拟的?
  • @Jonathan。你误会了,因为友谊永远不会被继承。

标签: c++ inheritance


【解决方案1】:

一种选择是使用私有嵌套结构来控制构造Base 的权限。

struct Base {
    template<class T>
    friend struct Der;
private:
    struct Permission {};
public:
    Base(Permission) {}
    virtual ~Base() = default;
};

template <class T>
struct Der : public virtual Base {
protected:
    using Permission = Base::Permission;
public:
    Der() : Base(Permission{}) {}
};

struct DerDer : Der<int>, Der<char> {
    DerDer() : Base(Der<int>::Permission{}) {}
};

现在编写构造函数有点尴尬,但构造Base 的唯一方法是为某些T 成为或继承Der&lt;T&gt;

【讨论】:

  • 我也会让 c'tor 受到保护,但是在标签调度上 +1
【解决方案2】:

我该如何解决这个问题?

最简单的解决方案是将Base::Base() 设为public 成员函数。

【讨论】:

  • 如果我这样做,那么它将允许Der 以外的另一个类从Base 继承?
  • @Jonathan。是的,它会
  • 这是我试图避免的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-21
  • 1970-01-01
  • 2012-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多