【问题标题】:Inheriting private CRTP constructor using friend declaration使用友元声明继承私有 CRTP 构造函数
【发布时间】:2018-11-23 00:27:25
【问题描述】:

我无法理解从基类继承构造函数的正确行为。 在我的特殊情况下,我有一个带有私有构造函数的 crtp-base 类,以防止基类(作为抽象类)的实例化。 现在,crtp-base 与派生类成为朋友,派生类使用 using 语句继承基类构造函数。这适用于默认、复制和移动构造函数,但对于自定义构造函数失败。有没有办法在不重新实现派生类中的所有构造函数的情况下实现这一点?

#include <iostream>

template <typename d_t>
class base
{
    friend d_t;

    base()
    {
        std::cout << "base: ctor()\n";
    }
    base(base const & other) = default;
    base(base && other) = default;

    base(int)
    {
        std::cout << "base: ctor()\n";
    }
};

class derived: public base<derived>
{
public:

   using base<derived>::base;
};

int main()
{
   derived d{};
   derived d1{d};
   derived d2{std::move(d1)};
   // derived d3{1};  //does not compile!
}

编辑

AFAIK cppreference 表示构造函数的可访问性不会被派生类中 using 声明的访问说明符更改,这与其他成员函数不同。但是我已经看到这种代码编译和运行,我不确定我是否正确理解了 using-declaration。 当然,我会进一步调查其他代码以了解发生了什么,但我想知道是否有隐藏的东西我可能会错过。

【问题讨论】:

  • friend d_t; 看起来不对?
  • @Yakk-AdamNevraumont 为什么?
  • _t 在 POSIX 中保留?
  • 让派生类成为朋友并没有多大意义,因为通过将所有内容设为受保护而不是私有,您将获得几乎相同的效果。主要区别在于,如果您从派生类派生其他类,但鉴于您使用的是 CRTP 模式,情况可能并非如此。因此,最后,我认为您使用了错误的工具来完成这项工作。
  • @Phil1970 是的。我可以保护它。如果我理解en.cppreference.com/w/cpp/language/using_declaration 正确,那么它甚至不应该工作。只是我见过这种代码编译,我完全无法解释为什么?所以我想知道是否有一点我不知道是什么使这项工作有效。

标签: c++ using friend crtp


【解决方案1】:

简短的回答是肯定的,只需在基类中公开它们即可。继承的构造函数在派生类中与在基类中具有相同的可访问性。无法在派生类中公开私有基类构造函数。

但是抽象基类无论如何都不能自己实例化。没有必要将它们的构造函数设为私有。

CRTP 与上述任何内容均无关。如果您只需要 friend 声明,那么您可以不使用该模式。

class base
{
public:
  base()
  {    
  }

  base(int)
  {
    std::cout << "base: ctor()\n";
  }

  virtual void foo() = 0;
};

class derived: public base
{
public:
  using base::base;

  void foo() override
  {
    // details...
  }
};

int main()
{
  derived d{};
  derived d1{d};
  derived d2{std::move(d1)};
  derived d3{1};  //Works!!
}

进一步阅读 cppreference:Using-declaration

【讨论】:

  • 感谢您的回复。我知道这可以解决问题,但是不能选择虚拟多态性。代码完全基于静态多态。
  • 原始问题中的“作为抽象类”是什么意思?
  • 抽象的意思是,为了避免 CRTP 基类的误用,它不应该在没有派生类的情况下是可实例化的。为了防止错误的继承(派生类为 CRTP 提供了错误的派生类型),您需要将构造函数设为私有并与派生类友好。这样只有派生类可以调用基类的构造函数,从而可以实例化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 2018-06-06
  • 1970-01-01
  • 2018-10-14
  • 1970-01-01
相关资源
最近更新 更多