【问题标题】:Is it possilbe to inherit private constructors with using in cpp >= 11是否可以在 cpp >= 11 中使用继承私有构造函数
【发布时间】:2021-01-26 16:07:42
【问题描述】:

有没有办法用 using 语句继承私有构造函数? 我尝试添加朋友声明,但似乎不起作用。

struct B;
struct A
{
private:
    A(int x) {}
    A(int y, double z) {}
    friend struct B;
};
struct B : public A
{
public:
    using A::A;
    //B(int x) : A(x) {}
    //B(int x, int y) : A(x, y) {}
};
void demo()
{
    B b1(5); // does not compile - implicit constructor is not accessible 
    B b2(4, 9.0);
}

我想知道是否有任何方法可以使用 using,因为如果我显式创建委托构造函数,friend 语句会起作用,所以这会不一致:

struct B;
struct A
{
private:
    A(int x) {}
    A(int y, double z) {}
    friend struct B;
};
struct B : public A
{
public:
    B(int x) : A(x) {} // OK
    B(int x, int y) : A(x, y) {}
};

void demo()
{
    B b1(5); // OK 
    B b2(4, 9.0);
}

【问题讨论】:

  • 也许只是措辞,但是当你继承时,一切都被继承了,还有私有成员,只是访问它们的问题
  • @idclev463035818 是的,你当然是对的。应该是“可以从继承者之外的范围继承和使用”.. 呃....你明白为什么我没有:)
  • 如何访问私有基类构造函数?您可以跳过“是否可以继承”部分,因为所有成员都是继承的。虽然,没关系,这个问题已经很清楚了,可以回答,但我不想让你变得更糟

标签: c++ c++11 constructor using


【解决方案1】:

继承构造函数的可访问性不受引入它们的 using 声明的可访问性影响。

[namespace.udecl](强调我的)

19 由 using 声明创建的同义词通常具有 成员声明的可访问性。命名的 using-declarator 构造函数不创建同义词;相反,额外的 如果构造函数在使用时可访问,则它们是可访问的 构造相应基类的对象,然后 using 声明的可访问性被忽略

由于您无法在main 中访问A 的构造函数,因此也无法在main 中构造B(您可以使用它来构造@987654326 @'s 和A's 在B 的范围内,因为友谊)。您需要明确说明某种转发 c'tor 以进行类外访问。由于您似乎追求“包罗万象”,因此可以使用一个相当简单的解决方案

template<typename... Args>
B(Args&&... args) : A(std::forward<Args>(args)...) {}

【讨论】:

  • “如果它们在用于构造相应基类的对象时可以访问”......似乎也没有以一致的方式工作。向实例化 B 的函数添加朋友语句不起作用,但它允许使用私有构造函数实例化 A。为什么?
  • @GonenI - 你在哪里添加了额外的朋友声明?友谊不是遗传的,也不是传递的。 B 的朋友不是 A 的朋友。无论哪种方式,友谊对可访问性的确切影响是另一回事,另一个问题。
  • 理想情况下,如果A(std::forward&lt;Args&gt;(args)...) 格式正确,您还可以应用 SFINAE 以仅让 B 的转发 ctor 参与重载决议。目前它将“抓住所有”并尝试转发到A 中不存在的构造函数,优先于B 中不完全匹配的唯一ctors(例如,它们可能对至少一个ctor 参数有一些转换序列)。
【解决方案2】:

我想知道是否有任何方法可以使用 using,因为如果我显式创建委托构造函数,friend 语句可以工作

不,当using 基类构造函数时,它们将保留原始protectedprivate 访问权限,因此如果您想使它们成为public,则需要在派生类中实现它们。将B 设为friend 并不会改变这一点。它只允许B 访问A 中的私有成员——函数和变量。

如果您希望派生类能够使用某些private 成员函数,您通常将这些成员函数改为protected

struct A {
protected:
    A(int x) {}
    A(int y, double z) {}
};

struct B : public A {
public:
    B(int x) : A(x) {}
    B(int y, double z) : A(y, z) {}
};

这样,您在设计A 时无需了解派生类,并且您还可以将private 成员变量保存在A private 中。

【讨论】:

  • 我发现这不一致,因为如果我在 B 中显式声明委托构造函数,A 中的朋友声明确实授予访问权限。
  • @GonenI 这是一个品味问题,取决于具体情况。使用friend,只有您授予访问权限的那些特定类才能使用这些函数——而且他们也可以完全访问您的private 成员变量,这通常不是人们想要的。使用protected,您可以提供任何想要扩展类的人都可以使用的函数,并且仍然保持私有成员变量的安全。
  • 不幸的是,我看到似乎对一个答案投了反对票,同时对另一个答案投了赞成票,因此有人可能会争辩说,有些人使用反对票来更好地表示另一个答案,而不是仅仅省略支持他们不太喜欢的答案。但这纯粹是猜测;匿名。无反馈的反对票总是忘恩负义的。
  • @TedLyngmo,IMO 更好,因为它是直接解决 OP 的部分。我的紫外线现在更牢固了:)。
  • 幸运的是@ArthurTacca 提出了一个理由,我对此表示赞赏。
【解决方案3】:

基于@StoryTeller - Unslander Monica 的回答,它解释了(继承的)构造函数可以在基类构造函数所在的位置访问,这是一个非常部分的解决方案,在某些情况下可以使用:

struct A
{
private:
    A(int x) {};
    A(int y, double z) {};
    friend struct B;
};
struct B : public A
{
public:
    friend void demo();
    using A::A;
};

void demo()
{
    B b1(5);
    B b2(4, 9.0);
}

int main() {
    demo();
}

【讨论】:

  • 你需要friend void demo(); in struct A
猜你喜欢
  • 1970-01-01
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 2021-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多