【问题标题】:A private inheritance in C++ [duplicate]C ++中的私有继承[重复]
【发布时间】:2014-01-02 21:08:58
【问题描述】:

在 C++ 中:假设我有一个类 X。这样的私有继承有什么区别:

class Deriv : private X
{
public:

//constructor etc

void method()
{
    usageOfMethodFromX();
}

};

还有这个:

class Deriv
{
private:
X * m_xinstance;

public:

//constructor etc

void method()
{
     m_xinstance->usageOfMethodFromX();
}

};

有什么区别不允许用派生类的成员代替私有继承,反之亦然?是一样的吗?

谢谢!

【问题讨论】:

  • 简短的回答是否定的。私有继承是一种“has-a”关系,与成员变量的关系相同。
  • @ZacHowland:不完全是:即使从具有virtual 成员函数的基类私有继承,这些成员也可以被覆盖!
  • 派生允许您利用基础子对象布局优化。
  • 不理解这里的反对意见。对于对 C++ 知之甚少的人来说,这是一个完全合理的问题。我所说的“很少”是指用不到 5 年的时间来学习 C++ 语言的方方面面。
  • @wheaties:我没有投反对票(我也不打算投反对票),但我猜反对票是因为问题是重复的......

标签: c++ inheritance


【解决方案1】:

如果您的基类具有virtual 函数,则存在细微差别:即使基类是私有继承的,也可以被覆盖:

#include <iostream>
class Base {
    virtual int do_f() { return 1; }
public:
    int f() { return this->do_f(); }
};
class Derived: Base {
    int do_f() { return 2; }
public:
    int g() { return this->f(); }
};
class Final: public Derived {
    int do_f() { return 3; }
};

int main() {
    Final final;
    std::cout << final.g() << '\n';
}

上面的代码将打印3 (live example)。

您的代码的另一个区别是分配内存的方法是在堆上分配内存。您可以通过将对象嵌入到派生对象中来避免这种堆分配。

【讨论】:

    【解决方案2】:

    有一个非常显着和明确的区别:考虑这个X

    class X {
      protected:
        void doSmth();
    };
    

    只有继承自 X 的类才能访问任何和所有受保护的成员(此处为 X::doSmth())。

    【讨论】:

    • 这绝不会回答他的任何问题......
    • @ZacHowland:不是吗?好吧,OP的问题是从类X私有继承或将其私有成员添加到类型之间是否有区别。答案是肯定的:如果X 具有您希望从“继承”类访问的受保护成员,则会产生巨大的影响,因为如果您只有一个成员,则不允许您访问其受保护的成员。
    • 您也不能访问私有继承的派生类中基类的受保护成员。
    • @ZacHowland:你确定吗? ideone.com/vSkTL9
    • @user1781713 也许我不清楚或误解了所说的内容。从派生类中调用它是有效的。我的意思是你不能称它为Derived d; d.doSmth(); 虽然,我记得不久前讨论过在私有继承的类中调用受保护方法的能力是一种疏忽,并没有真正的用例。
    【解决方案3】:

    是的。

    在继承模型中,两个对象的生命周期是交织在一起的。默认情况下会自动连接许多方法(operator=、构造函数、析构函数),将来可能会出现其他方法(operatorswap 又名:=:=default 其他运算符,如&lt;==)。最重要的是,virtual 方法覆盖和调用可以将调用路由到指向您的父接口(您可以提供其他接口,或者可以通过调用您的父方法来调用)的指针。

    如果你用X m_xinstance 替换你的X * m_xinstance,事情就会变得更接近。生命周期现在是绑定的,许多(全部?)连接的方法现在都以类似的方式连接起来。 virtual 的行为也很不一样。

    最后一个区别是,如果您的基类为空,则空基类优化可能发生在一种情况下,但不会发生成员实例。由于不同的对象必须有不同的地址,因此您的类成员的最小大小为1,而空的基类可以占用零内存。

    【讨论】:

    • 您不能使用dynamic_caststatic_cast 将派生类转换为指向基类的指针(在私有继承下)。 - Example.
    • @ZacHowland 不知道——固定答案。
    猜你喜欢
    • 2014-06-21
    • 2011-09-17
    • 1970-01-01
    • 2020-03-13
    • 2021-07-16
    • 2011-05-30
    • 2015-01-21
    • 2017-04-08
    • 2020-09-01
    相关资源
    最近更新 更多