c++中公共继承、私有继承和受保护继承之间的区别是什么?

我在SO上找到的所有问题都是针对具体案例的。


当前回答

Member in base class : Private   Protected   Public   

继承类型:对象继承为:

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public

其他回答

这三个关键字还在完全不同的上下文中用于指定可见性继承模型。

这个表收集了组件声明和继承模型的所有可能组合,表示在子类完全定义后对组件的最终访问。

上表的解释如下(看第一行):

如果一个组件被声明为公共的,并且它的类被继承为公共的,那么得到的访问是公共的。

一个例子:

 class Super {
    public:      int p;
    private:     int q;
    protected:   int r;
 };

 class Sub : private Super {};

 class Subsub : public Sub {};

Subsub类中变量p, q, r的访问结果为none。

另一个例子:

class Super {
    private:     int x;
    protected:   int y;
    public:      int z;
 };
class Sub : protected Super {};

类Sub中对变量y, z的访问受到保护,对变量x的访问为none。

一个更详细的例子:

class Super {
private:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};
int main(void) {
    Super object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

现在让我们定义一个子类:

class Sub : Super { };

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

定义了一个名为Sub的类,它是一个名为Super的类的子类,或者这个子类是从Super类派生的。 子类既不引入新变量也不引入新函数。这是否意味着子类的任何对象都继承了父类之后的所有特征,实际上是父类对象的副本?

不。它不是。

如果我们编译下面的代码,我们只会得到编译错误,表示put和get方法不可访问。为什么?

当省略可见性说明符时,编译器假定我们将应用所谓的私有继承。这意味着所有的公共超类组件都变成了私有访问,私有超类组件将根本无法访问。因此,这意味着不允许在子类中使用后者。

我们必须通知编译器我们想要保留以前使用的访问策略。

class Sub : public Super { };

不要被误导:这并不意味着私人组件的超 类(如存储变量)将转换为公共类 有点神奇。私有组件将保持私有、公开 将继续公开。

子类的对象可以做“几乎”与从超类创建的它们的哥哥姐姐相同的事情。“几乎”是因为作为子类的事实也意味着该类失去了对超类的私有组件的访问权。子类的成员函数不能直接操作存储变量。

这是一个非常严重的限制。有什么解决办法吗?

Yes.

第三个访问级别称为受保护。关键字protected意味着标记了它的组件在被任何子类使用时表现得像一个公共组件,而对其他组件看起来像一个私有组件。——这只适用于公共继承的类(比如我们例子中的Super类)——

class Super {
protected:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};

class Sub : public Super {
public:
    void print(void) {cout << "storage = " << storage;}
};

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get() + 1);
    object.print();
    return 0;
}

正如你在示例代码中看到的,我们给子类添加了一个新功能,它做了一件重要的事情:它从超类访问存储变量。

如果变量被声明为私有,这是不可能的。 在main函数的作用域中,变量仍然是隐藏的,所以如果你这样写:

object.storage = 0;

编译器会告诉你这是一个错误:'int Super::storage'是受保护的。

最后,最后一个程序将产生以下输出:

storage = 101

我试着用下面的一张图片来解释继承。

主要的要点是父类的私有成员永远不能从派生类/子类直接访问,但是您可以使用父类的成员函数来访问父类的私有成员。 私有变量始终存在于派生类中,但派生类不能访问它。这就像他们的,但你不能用自己的眼睛看到,但如果你问一个来自父母类的人,然后他可以向你描述。

任何继承自您的类的类都可以访问受保护的数据成员。但是,私有数据成员不能。假设我们有以下内容:

class MyClass {
    private:
        int myPrivateMember;    // lol
    protected:
        int myProtectedMember;
};

从扩展到这个类,引用这个。myPrivateMember不能工作。然而,这。myProtectedMember意志。这个值仍然是封装的,所以如果我们有一个myObj类的实例化,那么myObj。myProtectedMember不能工作,所以它的功能类似于私有数据成员。

限制继承的可见性将使代码无法看到某些类继承了另一个类:从派生类到基类的隐式转换将不起作用,从基类到派生类的static_cast也将不起作用。

只有类的成员/友元才能看到私有继承,只有类的成员/友元和派生类才能看到受保护继承。

公共继承

是一种继承。一个按钮就是一个窗口,只要需要一个窗口,就可以传递一个按钮。 类按钮:公共窗口{};

保护继承

implemented-in-terms-of保护。很少有用。在boost::compressed_pair中使用从空类派生并使用空基类优化来节省内存(下面的例子没有使用模板来保持在点上): 结构empty_pair_impl: protected empty_class_1 {non_empty_class_2秒;}; 结构对:private empty_pair_impl { Non_empty_class_2 &second() { 返回这个- >第二; } Empty_class_1 &first() { 返回*;//注意我们返回*this! } };

私有继承

Implemented-in-terms-of. The usage of the base class is only for implementing the derived class. Useful with traits and if size matters (empty traits that only contain functions will make use of the empty base class optimization). Often containment is the better solution, though. The size for strings is critical, so it's an often seen usage here template<typename StorageModel> struct string : private StorageModel { public: void realloc() { // uses inherited function StorageModel::realloc(); } };


公共成员

总 类对{ 公众: 首先第一; 第二第二; }; 访问器 类窗口{ 公众: int getWidth(); };

保护成员

提供对派生类的增强访问 类堆栈{ 保护: 矢量c < >元素; }; 类窗口{ 保护: void registerClass(window_descriptor w); };

私有成员

保持实现细节 类窗口{ 私人: int宽度; };


请注意,c风格强制转换有意允许以已定义和安全的方式将派生类强制转换为受保护或私有基类,也可以强制转换为其他方向。无论如何都应该避免这种情况,因为它会使代码依赖于实现细节——但如果有必要,您可以使用这种技术。

为了回答这个问题,我想先用我自己的话描述一下成员的访问器。如果你已经知道这一点,那就跳到标题“下一步:”。

我知道有三种访问器:公共的、受保护的和私有的。

Let:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};

所有知道Base的都知道Base包含publicMember。 只有子节点(及其子节点)知道Base包含protectedMember。 除了Base,没有人知道privateMember。

“意识到”,我的意思是“承认存在,从而能够获得”。

下一个:

同样的情况也发生在公共、私有和受保护的继承上。让我们考虑一个类Base和一个继承自Base的类Child。

如果继承是公共的,那么所有知道Base和Child的东西也知道Child从Base继承。 如果继承是受保护的,那么只有Child及其子元素知道它们从Base继承。 如果继承是私有的,那么除了Child之外没有人知道继承。