C++中的公共、私有和受保护继承有什么区别?

C++中的publicprivateprotected继承有什么区别?

我在SO上找到的所有问题都涉及具体案例。

739842 次浏览

它与基类的公共成员如何从派生类公开有关。

  • public->基类的public成员将是public(通常是默认值)
  • protected->基类的公共成员将受到保护
  • 私有->基类的公共成员将是私有的

正如litb指出的,公共继承是你会在大多数编程语言中看到的传统继承。这是它模拟了一种“IS-A”关系。私有继承,C++特有的东西,是一种“在条款中实现”的关系。也就是说,你想在派生类中的公共接口使用,但不希望派生类的用户访问该接口。许多人认为在这种情况下你应该聚合基类,也就是说,不是让基类作为私有基类,而是让派生类的成员重用基类的功能。

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

我知道有三个访问器:publicprotectedprivate

让:

class Base {public:int publicMember;protected:int protectedMember;private:int privateMember;};
  • 所有知道Base的东西也知道Base包含publicMember
  • 只有孩子(和他们的孩子)知道Base包含protectedMember
  • 除了Base,没有人知道privateMember

通过“意识到”,我的意思是“承认存在,从而能够访问”。

下一篇:

公共、私有和受保护的继承也是如此。让我们考虑一个类Base和一个从Base继承的类Child

  • 如果继承是public,那么所有知道BaseChild的东西也知道Child继承自Base
  • 如果继承为protected,则只有Child及其子代知道它们继承自Base
  • 如果继承为private,则除了Child之外没有人知道继承。

它本质上是对派生类中基类的公共和受保护成员的访问保护。使用公共继承,派生类可以看到基的公共和受保护成员。使用私有继承,它不能。使用protected,派生类和从其派生的任何类都可以看到它们。

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

class MyClass {private:int myPrivateMember;    // lolprotected:int myProtectedMember;};

从您的扩展到此类,引用this.myPrivateMember将不起作用。但是,this.myProtectedMember会。该值仍然被封装,因此如果我们有一个名为myObj的此类实例化,那么myObj.myProtectedMember将不起作用,因此它在功能上类似于私有数据成员。

总结:

  • 私有:除了类内,没有人可以看到它
  • 受保护:Private+派生类可以看到它
  • 公众:世界可以看到

继承时,您可以(在某些语言中)按特定方向更改数据成员的保护类型,例如从protected更改为public。

如果你从另一个类公开继承,每个人都知道你在继承,任何人都可以通过基类指针多态地使用你。

如果您以保护方式继承,则只有您的子类才能以多态方式使用您。

如果你私下继承,只有你自己才能执行父类方法。

这基本上象征着其他班级对你和你父母班级关系的了解

class A{public:int x;protected:int y;private:int z;};
class B : public A{// x is public// y is protected// z is not accessible from B};
class C : protected A{// x is protected// y is protected// z is not accessible from C};
class D : private A    // 'private' is default for classes{// x is private// y is private// z is not accessible from D};

重要提示:类B、C和D都包含变量x、y和z。这只是访问问题。

关于受保护和私有继承的用法,您可以阅读这里

公共继承为IS-A关系建模。随着

class B {};class D : public B {};

每个D是一个B

私有继承为IS-IMPLEMENTED-USING关系(或任何称为的关系)建模。随着

class B {};class D : private B {};

D没有B,但每个D在其实现中都使用其B。私有继承总是可以通过使用包含来消除:

class B {};class D {private:B b_;};

这个D也可以使用B实现,在这种情况下使用它的b_。与继承相比,包含类型之间的耦合不那么紧密,因此通常应该首选它。有时使用包含而不是私有继承不如私有继承方便。通常这是懒惰的蹩脚借口。

我认为没有人知道protected继承模型是什么。至少我还没有看到任何令人信服的解释。

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

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

公共继承

  1. IS-继承。按钮是一个窗口,任何需要窗口的地方,也可以传递一个按钮。

    class button : public window { };

protected inheritance

  1. Protected implemented-in-terms-of. Rarely useful. Used in boost::compressed_pair to derive from empty classes and save memory using empty base class optimization (example below doesn't use template to keep being at the point):

    struct empty_pair_impl : protected empty_class_1{ non_empty_class_2 second; };
    struct pair : private empty_pair_impl {non_empty_class_2 &second() {return this->second;}
    empty_class_1 &first() {return *this; // notice we return *this!}};

private inheritance

  1. 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 functionStorageModel::realloc();}};

public member

  1. Aggregate

    class pair {public:First first;Second second;};
  2. Accessors

    class window {public:int getWidth() const;};

protected member

  1. Providing enhanced access for derived classes

    class stack {protected:vector<element> c;};
    class window {protected:void registerClass(window_descriptor w);};

private member

  1. Keep implementation details

    class window {private:int width;};

Note that C-style casts purposely allows casting a derived class to a protected or private base class in a defined and safe manner and to cast into the other direction too. This should be avoided at all costs, because it can make code dependent on implementation details - but if necessary, you can make use of this technique.

私人:

基类的私有成员只能由该基类的成员访问。

公众:

基类的公共成员可以由该基类的成员、其派生类的成员以及基类和派生类之外的成员访问。

保护:

基类的受保护成员可以由基类的成员及其派生类的成员访问。


简而言之:

私人:基础

保护: base+派生

公共: base+派生+任何其他成员

Member in base class : Private   Protected   Public

继承类型对象继承为

Private            :   Inaccessible   Private     PrivateProtected          :   Inaccessible   Protected   ProtectedPublic             :   Inaccessible   Protected   Public

我找到了一个简单的答案,所以想把它贴出来供我将来参考。

来自链接http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/

class Base{public:int m_nPublic; // can be accessed by anybodyprivate:int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)protected:int m_nProtected; // can be accessed by Base member functions, or derived classes.};
class Derived: public Base{public:Derived(){// Derived's access to Base members is not influenced by the type of inheritance used,// so the following is always true:
m_nPublic = 1; // allowed: can access public base members from derived classm_nPrivate = 2; // not allowed: can not access private base members from derived classm_nProtected = 3; // allowed: can access protected base members from derived class}};
int main(){Base cBase;cBase.m_nPublic = 1; // allowed: can access public members from outside classcBase.m_nPrivate = 2; // not allowed: can not access private members from outside classcBase.m_nProtected = 3; // not allowed: can not access protected members from outside class}
Accessors    | Base Class | Derived Class | World—————————————+————————————+———————————————+———————public       |      y     |       y       |   y—————————————+————————————+———————————————+———————protected    |      y     |       y       |   n—————————————+————————————+———————————————+———————private      |            |               |or         |      y     |       n       |   nno accessor  |            |               |
y: accessiblen: not accessible

基于Java的这个示例……我认为一个小表值一千个字:)

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

此表收集了组件声明和继承模型的所有可能组合,在子类完全定义时呈现对组件的结果访问。

输入图片描述

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

如果一个组件被声明为public,并且它的类被继承为public,则结果的访问public

举个例子:

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

Subsub中变量pqr的最终访问权限为没有

另一个例子:

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

小组中变量yz的结果访问权限为保护,变量x的结果访问权限为没有

更详细的例子:

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的类的子类,或者Sub类派生自Super类。Sub类既不引入新变量也不引入新函数。这是否意味着Sub类的任何对象在Super类实际上是Super类对象的副本之后继承了所有特征?

。它没有。

如果我们编译下面的代码,我们只会得到编译错误,说putget方法无法访问。为什么?

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

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

class Sub : public Super { };

别被误导了:这并不意味着超级系统的私有组件类(如存储变量)将在私人组件将保持私人公共将保持公共

Sub类的对象可以做“几乎”与从Super类创建的较老的兄弟姐妹相同的事情。“几乎”因为作为子类的事实也意味着类失去了对父类私有组件的访问权限。我们不能编写Sub类的成员函数,它能够直接操作存储变量。

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

第三个访问级别称为保护。关键字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;}

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

如果变量被声明为私有,则不可能。在主函数作用域中,变量仍然隐藏,因此如果您编写以下内容:

object.storage = 0;

编译器会告诉你它是一个error: 'int Super::storage' is protected

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

storage = 101

1)公共继承

a.在派生类中无法访问Base类的私有成员。

b. Base类的受保护成员在Derive类中仍然受到保护。

c. Base类的公共成员在Derive类中仍然是公共的。

因此,其他类可以通过派生类对象使用Base类的公共成员。

2)受保护的继承

a.在派生类中无法访问Base类的私有成员。

b. Base类的受保护成员在Derive类中仍然受到保护。

基本类的公共成员也成为派生类的受保护成员。

因此,其他类不能通过Derive类对象使用Base类的公共成员;但它们可用于Derive的子类。

3)私人继承

a.在派生类中无法访问Base类的私有成员。

b. Base类的受保护成员和公共成员成为Derive类的私有成员。

因此,Base类的任何成员都不能被其他类通过派生类对象访问,因为它们在派生类中是私有的。所以,即使是派生的子类类无法访问它们。

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

主要要点是父类的私有成员永远不能从派生/子类直接访问,但您可以使用父类的成员函数来访问父类的私有成员。私有变量总是存在于派生类中,但派生类不能访问它。就像他们一样,但你不能亲眼看到,但如果你问某人形成父类,那么他可以向你描述它。继承映射cpp