C++ 私有、公共和受保护继承之间的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/860339/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:37:41  来源:igfitidea点击:

Difference between private, public, and protected inheritance

c++inheritanceencapsulationaccess-specifierc++-faq

提问by Anzurio

What is the difference between public, private, and protectedinheritance in C++?

是什么区别publicprivate以及protected在继承C ++?

All of the questions I've found on SO deal with specific cases.

我在 SO 上发现的所有问题都涉及特定案例。

回答by Kirill V. Lyadvinsky

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
};

IMPORTANT NOTE: Classes B, C and D all contain the variables x, y and z. It is just question of access.

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

About usage of protected and private inheritance you could read here.

关于受保护和私有继承的使用,您可以在此处阅读。

回答by Anzurio

To answer that question, I'd like to describe member's accessors first in my own words. If you already know this, skip to the heading "next:".

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

There are three accessors that I'm aware of: public, protectedand private.

我知道三个访问器:public,protectedprivate.

Let:

让:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Everything that is aware of Baseis also aware that Basecontains publicMember.
  • Only the children (and their children) are aware that Basecontains protectedMember.
  • No one but Baseis aware of privateMember.
  • 知道的一切Base也知道Base包含publicMember.
  • 只有孩子(和他们的孩子)知道Base包含protectedMember.
  • 却无人Base知晓privateMember

By "is aware of", I mean "acknowledge the existence of, and thus be able to access".

“知道”,我的意思是“承认存在,从而能够访问”。

next:

下一个:

The same happens with public, private and protected inheritance. Let's consider a class Baseand a class Childthat inherits from Base.

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

  • If the inheritance is public, everything that is aware of Baseand Childis also aware that Childinherits from Base.
  • If the inheritance is protected, only Child, and its children, are aware that they inherit from Base.
  • If the inheritance is private, no one other than Childis aware of the inheritance.
  • 如果继承public,一切是知道的Base,并Child也意识到Child继承Base
  • 如果继承是protected,则只有Child及其子代知道他们从 继承Base
  • 如果继承是private,除了Child知道继承之外,没有人知道。

回答by Johannes Schaub - litb

Limiting the visibility of inheritance will make code not able to see that some class inherits another class: Implicit conversions from the derived to the base won't work, and static_castfrom the base to the derived won't work either.

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

Only members/friends of a class can see private inheritance, and only members/friends and derived classes can see protected inheritance.

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

publicinheritance

公共继承

  1. IS-A inheritance. A button is-a window, and anywhere where a window is needed, a button can be passed too.

    class button : public window { };
    
  1. IS-A 继承。一个按钮就是一个窗口,任何需要窗口的地方,也可以传递一个按钮。

    class button : public window { };
    

protectedinheritance

受保护的继承

  1. Protected implemented-in-terms-of. Rarely useful. Used in boost::compressed_pairto 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!
      }
    };
    
  1. 受保护的实施。很少有用。用于boost::compressed_pair从空类派生并使用空基类优化节省内存(下面的示例不使用模板来保持原状):

    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!
      }
    };
    

privateinheritance

私人继承

  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 containmentis 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();
      }
    };
    
  1. 实施。基类的用法仅用于实现派生类。对特征有用,如果大小很重要(仅包含函数的空特征将使用空基类优化)。不过,通常遏制是更好的解决方案。字符串的大小很关键,所以这里经常看到它的用法

    template<typename StorageModel>
    struct string : private StorageModel {
    public:
      void realloc() {
        // uses inherited function
        StorageModel::realloc();
      }
    };
    


publicmember

公众会员

  1. Aggregate

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

    class window {
    public:
        int getWidth() const;
    };
    
  1. 总计的

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

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

protectedmember

受保护成员

  1. Providing enhanced access for derived classes

    class stack {
    protected:
      vector<element> c;
    };
    
    class window {
    protected:
      void registerClass(window_descriptor w);
    };
    
  1. 为派生类提供增强的访问

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

privatemember

私人会员

  1. Keep implementation details

    class window {
    private:
      int width;
    };
    
  1. 保留实施细节

    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.

请注意,C 风格的强制转换特意允许以已定义且安全的方式将派生类强制转换为受保护或私有的基类,并允许将其强制转换为另一个方向。应该不惜一切代价避免这种情况,因为它会使代码依赖于实现细节——但如果有必要,您可以使用这种技术。

回答by BugShotGG

These three keywords are also used in a completely different context to specify the visibility inheritance model.

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

This table gathers all of the possible combinations of the component declaration and inheritance model presenting the resulting access to the components when the subclass is completely defined.

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

enter image description here

在此处输入图片说明

The table above is interpreted in the following way (take a look at the first row):

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

if a component is declaredas publicand its class is inheritedas publicthe resulting accessis public.

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

An example:

一个例子:

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

 class Sub : private Super {};

 class Subsub : public Sub {};

The resulting access for variables p, q, rin class Subsubis none.

变量产生的访问pqrSubsub没有

Another example:

另一个例子:

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

The resulting access for variables y, zin class Subis protectedand for variable xis none.

结果对变量的访问yz在类Sub 中受保护的,而对变量的访问x

A more detailed example:

一个更详细的例子:

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;
}

Now lets define a subclass:

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

class Sub : Super { };

int main(void) {
    Sub object;

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

The defined class named Sub which is a subclass of class named Superor that Subclass is derived from the Superclass. The Subclass introduces neither new variables nor new functions. Does it mean that any object of the Subclass inherits all the traits after the Superclass being in fact a copy of a Superclass' objects?

定义的名为 Sub 的类是名为类的子类,Super或者Sub该类是从Super该类派生的。该Sub课程介绍既不是新的变量,也没有新的功能。这是否意味着Sub该类的任何对象在类Super实际上是Super类对象的副本之后继承了所有特征?

No. It doesn't.

没有。它没有。

If we compile the following code, we will get nothing but compilation errors saying that putand getmethods are inaccessible. Why?

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

When we omit the visibility specifier, the compiler assumes that we are going to apply the so-called private inheritance. It means that all publicsuperclass components turn into privateaccess, private superclass components won't be accessible at all. It consequently means that you are not allowed to use the latter inside the subclass.

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

We have to inform the compiler that we want to preserve the previously used access policy.

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

class Sub : public Super { };

Don't be misled: it doesn't mean that private components of the Super class (like the storage variable) will turn into public ones in a somewhat magical way. Privatecomponents will remain private, publicwill remain public.

不要被误导:这并不意味着 Super 类的私有组件(如存储变量)会以某种神奇的方式变成公共组件。私有组件将保持私有公共将保持公开

Objects of the Subclass may do "almost" the same things as their older siblings created from the Superclass. "Almost"because the fact of being a subclass also means that the class lost access to the private components of the superclass. We cannot write a member function of the Subclass which would be able to directly manipulate the storage variable.

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

This is a very serious restriction. Is there any workaround?

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

Yes.

是的

The third access level is called protected. The keyword protected means that the component marked with it behaves like a public one when used by any of the subclasses and looks like a private one to the rest of the world. -- This is true only for the publicly inherited classes (like the Super class in our example)--

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

As you see in the example code we a new functionality to the Subclass and it does one important thing: it accesses the storage variable from the Super class.

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

It wouldn't be possible if the variable was declared as private. In the main function scope the variable remains hidden anyway so if you write anything like:

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

object.storage = 0;

The compiler will inform you that it is an error: 'int Super::storage' is protected.

编译器会通知你它是一个error: 'int Super::storage' is protected.

Finally, the last program will produce the following output:

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

storage = 101

回答by Doug T.

It has to do with how the public members of the base class are exposed from the derived class.

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

  • public -> base class's public members will be public (usually the default)
  • protected -> base class's public members will be protected
  • private -> base class's public members will be private
  • public -> 基类的公共成员将是公共的(通常是默认的)
  • protected -> 基类的公共成员将受到保护
  • private -> 基类的公共成员将是私有的

As litb points out, public inheritance is traditional inheritance that you'll see in most programming languages. That is it models an "IS-A" relationship. Private inheritance, something AFAIK peculiar to C++, is an "IMPLEMENTED IN TERMS OF" relationship. That is you want to usethe public interface in the derived class, but don't want the user of the derived class to have access to that interface. Many argue that in this case you should aggregate the base class, that is instead of having the base class as a private base, make in a member of derived in order to reuse base class's functionality.

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

回答by kinshuk4

Member in base class : Private   Protected   Public   

Inheritance type:             Object inherited as:

继承类型:             对象继承为

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

回答by yuvi

1) Public Inheritance:

1) 公共继承

a. Private members of Base class are not accessible in Derived class.

一种。在派生类中无法访问基类的私有成员。

b. Protected members of Base class remain protected in Derived class.

湾 基类的受保护成员在派生类中仍受保护。

c. Public members of Base class remain public in Derived class.

C。基类的公共成员在派生类中仍然是公共的。

So, other classes can use public members of Base class through Derived class object.

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

2) Protected Inheritance:

2) 受保护的继承

a. Private members of Base class are not accessible in Derived class.

一种。在派生类中无法访问基类的私有成员。

b. Protected members of Base class remain protected in Derived class.

湾 基类的受保护成员在派生类中仍受保护。

c. Public members of Base class too become protected members of Derived class.

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

So, other classes can't use public members of Base class through Derived class object; but they are available to subclass of Derived.

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

3) Private Inheritance:

3)私有继承

a. Private members of Base class are not accessible in Derived class.

一种。在派生类中无法访问基类的私有成员。

b. Protected & public members of Base class become private members of Derived class.

湾 基类的受保护和公共成员成为派生类的私有成员。

So, no members of Base class can be accessed by other classes through Derived class object as they are private in Derived class. So, even subclass of Derived class can't access them.

因此,其他类不能通过派生类对象访问基类的成员,因为它们在派生类中是私有的。因此,即使是 Derived 类的子类也无法访问它们。

回答by sbi

Public inheritance models an IS-A relationship. With

公共继承对 IS-A 关系建模。和

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

every Dis aB.

每个D都是一个B.

Private inheritance models an IS-IMPLEMENTED-USING relationship (or whatever that's called). With

私有继承建模了一个 IS-IMPLEMENTED-USING 关系(或任何所谓的关系)。和

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

a Dis nota B, but every Duses its Bin its implementation. Private inheritance can always be eliminated by using containment instead:

一个D不是一个B,但每一个D使用它B的实施。私有继承总是可以通过使用包含来消除:

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

This D, too, can be implemented using B, in this case using its b_. Containment is a less tight coupling between types than inheritance, so in general it should be preferred. Sometimes using containment instead of private inheritance is not as convenient as private inheritance. Often that's a lame excuse for being lazy.

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

I don't think anyone knows what protectedinheritance models. At least I haven't seen any convincing explanation yet.

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

回答by Arkaitz Jimenez

If you inherit publicly from another class, everybody knows you are inheriting and you can be used polymorphically by anyone through a base class pointer.

如果您从另一个类公开继承,则每个人都知道您正在继承,并且任何人都可以通过基类指针以多态方式使用您。

If you inherit protectedly only your children classes will be able to use you polymorphically.

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

If you inherit privately only yourself will be able to execute parent class methods.

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

Which basically symbolizes the knowledge the rest of the classes have about your relationship with your parent class

这基本上象征着其他班级对您与父班级关系的了解

回答by Andrew Noyes

Protected data members can be accessed by any classes that inherit from your class. Private data members, however, cannot. Let's say we have the following:

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

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

From within your extension to this class, referencing this.myPrivateMemberwon't work. However, this.myProtectedMemberwill. The value is still encapsulated, so if we have an instantiation of this class called myObj, then myObj.myProtectedMemberwon't work, so it is similar in function to a private data member.

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