C++ 子类真的继承私有成员变量吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14270631/
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 18:10:33  来源:igfitidea点击:

Do Sub-Classes Really Inherit Private Member Variables?

c++inheritanceprivatemembers

提问by TorbenC

Basically as far as I know, when you create a base class with a public, protected, and private section and variables/functions in each the public and protected sections will get inherited into the appropriate section of the sub-class (defined by class subclass : private base, which will take all public and protected members of base and put them into public, changing the word private to public puts them all in public and changing it to protected puts them all into protected).

基本上据我所知,当您创建一个带有公共、受保护和私有部分以及每个公共和受保护部分中的变量/函数的基类时,将继承到子类的适当部分(由类子类定义) : private base,它将获取所有公共和受保护的成员并将它们放入公共中,将私有一词更改为公共将它们全部放入公共并将其更改为受保护将它们全部放入受保护中)。

So, when you create a sub-class you never receive anything from the private section of the previous class (the base class in this case), if this is true then an object of the sub-class should never have it's own version of a private variable or function from the base class correct?

所以,当你创建一个子类时,你永远不会从前一个类(在这种情况下是基类)的私有部分收到任何东西,如果这是真的,那么子类的对象永远不应该有它自己的版本基类中的私有变量或函数是否正确?

Let's run over an example:

让我们来看一个例子:

#include <iostream>

class myClass     // Creates a class titled myClass with a public section and a private section.
{
public:
  void setMyVariable();
  int getMyVariable();
private:
  int myVariable;     // This private member variable should never be inherited.
};

class yourClass : public myClass {};    // Creates a sub-class of myClass that inherits all the public/protected members into  the
// public section of yourClass. This should only inherit setMyVariable()
// and getMyVariable() since myVariable is private. This class does not over-ride any
// functions so it should be using the myClass version upon each call using a yourClass
// object. Correct?

int main()
{
  myClass myObject;           // Creates a myClass object called myObject.
  yourClass yourObject;       // Creates a yourClass object called yourObject
  yourObject.setMyVariable(); // Calls setMyVariable() through yourObject. This in turn calls the myClass version of it    because
  // there is no function definition for a yourClass version of this function. This means that this
  // can indeed access myVariable, but only the myClass version of it (there isn't a yourClass
  // version because myVariable is never inherited).

  std::cout << yourObject.getMyVariable() << std::endl;   // Uses the yourClass version of getMyVariable() which in turn
  // calls the myClass version, thus it returns the myClass myVariable
  // value. yourClass never has a version of myVariable Correct?

  std::cout << myObject.getMyVariable() << std::endl;     // Calls the myClass version of getMyVariable() and prints myVariable.

  return 0;
}

void myClass::setMyVariable()
{
  myVariable = 15;        // Sets myVariable in myClass to 15.
}

int myClass::getMyVariable()
{
  return myVariable;      // Returns myVariable from myClass.
}

Now, in theory based on what I think, this should print: 15 15 Due to it simply always using the myClass version of the functions (thus using the myClass myVariable). But, strangely, this is not the case. The result of running this program prints: 15 0 This makes me wonder, are we actually not only inheriting myVariable, but do we also have the ability to mess around with it? Clearly this is creating an alternate version of myVariable somehow otherwise there wouldn't be a 0 for the myClass version. We are indeed editing a second copy of myVariable by doing all this.

现在,理论上基于我的想法,这应该打印:15 15 因为它总是使用函数的 myClass 版本(因此使用 myClass myVariable)。但是,奇怪的是,情况并非如此。运行这个程序的结果打印: 15 0 这让我想知道,我们实际上不仅继承了 myVariable ,而且我们还有能力乱搞它吗?显然,这是在以某种方式创建 myVariable 的替代版本,否则 myClass 版本不会有 0。通过执行所有这些操作,我们确实在编辑 myVariable 的第二个副本。

Can someone please explain this all to me, this has torn apart my understanding of inheritance.

谁能给我解释一下这一切,这已经撕裂了我对继承的理解。

回答by didierc

Basically as far as I know, when you create a base class with a public, protected, and private section and variables/functions in each the public and protected sections will get inherited into the appropriate section of the sub-class (defined by class subclass : private base, which will take all public and private members of base and put them into public, changing the word private to public puts them all in public and changing it to protected puts them all into protected).

基本上据我所知,当您创建一个带有公共、受保护和私有部分以及每个公共和受保护部分中的变量/函数的基类时,将继承到子类的适当部分(由类子类定义) :private base,它将获取base的所有公共和私有成员并将它们放入public中,将private更改为public将它们全部放入public并将其更改为protected将它们全部放入protected中)。

There's a bit of confusion in this statement.

这个说法有点混乱。

Recall that inheritance is defined for classes and structs in C++. Individual objects (ie. instances) do not inherit from other objects. Constructing an object using other objects is called composition.

回想一下,继承是为 C++ 中的类和结构定义的。单个对象(即实例)不从其他对象继承。使用其他对象构造一个对象称为组合

When a class inherits from another class, it gets everything from that class, but the access level of the inherited fields may inhibit their use within the inheritor.

当一个类从另一个类继承时,它从该类中获取所有内容,但继承字段的访问级别可能会禁止它们在继承者中使用。

Furthermore, there are 3 kinds of inheritance for classes: private(which is the default), protected, and public. Each of them changes the access level of a class properties and methods when inherited by a subclass.

此外,类有 3 种继承:(private这是默认值)protected、 和public。当被子类继承时,它们中的每一个都会更改类属性和方法的访问级别。

If we order the access levels in this manner: public, protected, private, from the least protected to the most protected, then we can define the inheritance modifiers as raising the access levels of the inherited class fields to at least the level they designate, in the derived class (ie. the class inheriting).

如果我们以这种方式对访问级别进行排序:public, protected, private, 从最不受保护到最受保护,那么我们可以将继承修饰符定义为将继承的类字段的访问级别至少提高到它们指定的级别,在派生的类(即继承的类)。

For instance, if class Binherits from class Awith the protectedinheritance modifier:

例如,如果类B继承自A具有protected继承修饰符的类:

  class B : protected A { /* ... */ };

then all the fields from Awill have at least the protectedlevel in B:

那么来自的所有字段A将至少具有以下protected级别B

  • publicfields become protected(publiclevel is raised to protected),
  • protectedfields stay protected(same access level, so no modification here),
  • privatefields stay private(the access level is already above the modifier)
  • public字段变为protectedpublic级别提高到protected),
  • protected字段保持protected不变(相同的访问级别,所以这里没有修改),
  • private字段保持private(访问级别已经在修饰符之上)

回答by Beta

"When you create a sub-class you never receive anything from the private section of the [base class]. If this is true then an object of the sub-class should never have it's own version of a private variable or function from the base class, correct?"

“当你创建一个子类时,你永远不会从 [基类] 的私有部分收到任何东西。如果这是真的,那么子类的对象永远不应该拥有它自己版本的来自基类的私有变量或函数上课对吗?”

No. The derived class inherits all the members of the base class, including the private ones. An object of the inherited class hasthose private members, but does not have direct accessto them. It has access to public members of the base class that may have access to those members, but it (the derived class) may not have new member functions with such access:

否。派生类继承基类的所有成员,包括私有成员。继承类的对象具有这些私有成员,但不能直接访问它们。它可以访问可以访问这些成员的基类的公共成员,但它(派生类)可能没有具有此类访问权限的新成员函数:

class yourClass : public myClass
{
public:
  void playByTheRules()
  {
    setMyVariable(); // perfectly legal, since setMyVariable() is public
  }

  void tamperWithMyVariable()
  {
    myVariable = 20; // this is illegal and will cause a compile-time error
  }
};

回答by us2012

myObjectand yourObjectare two different objects! Why should they share anything?

myObject并且yourObject是两个不同的对象!他们为什么要分享任何东西?

Think about it that way: Forget about inheritance and suppose you have a class Personwith private int age;and public void setAge (int age) {...}. You then instantiate two objects:

这样想:忘记继承并假设您有一个Person带有private int age;and的类public void setAge (int age) {...}。然后实例化两个对象:

Person bob;
Person bill;
bob.setAge(35);

Would you expect Bill to be 35 now, too? You wouldn't, right? Similarly, your myObjectdoesn't share its data with yourObject.

你希望比尔现在也 35 岁吗?你不会,对吧?同样,您myObject不会与yourObject.



In response to your comment:

回应你的评论:

The class yourClassinherits from myClass. That means that both yourObjectand myObjecthave their own myVariable, the latter obviously by definition, the former inherited from myClass.

该类yourClass继承自myClass. 这意味着,双方yourObjectmyObject有自己的myVariable,显然被定义后者,前者从继承myClass

回答by Anurag Kalia

Physically, every single member( including member functions) of base class goes into the subclass. Doesn't matter if they are private. Doesn't matter if you inherit them publically/protected-ly/privately. So in your example, yourClasscontains all three of getMyVariable(), setMyVariable()and myVariable. All this is pretty simple, okay?

在物理上,基类的每个成员(包括成员函数)都进入子类。如果他们是私人的并不重要。如果您公开/受保护/私下继承它们并不重要。因此,在您的示例中,yourClass包含getMyVariable(),setMyVariable()和 的所有三个myVariable。这一切都很简单,好吗?

What matters is how we can access them. It is like when a file is deleted on your system. So, you should first understand the difference between a member being not there and a member being there but inaccessible. Assume for now that all inheritance takes place publically. Then, all public members of base class are public in derived class, protected members are protected and private members are inaccessible. They are inaccessible and not non-existent because there can be some member functions in protected and public sections in base class which access the private members of base class. Thus, we need all those private members of base which are accessed by public and protected member functions of base, for their functionality. Since there is no way that we can determine which member is needed by which member function in a simple manner, we include all private members of the base class in derived class. All this simply means that in a derived class, a private member can be modified by only through the base class' member functions.

重要的是我们如何访问它们。就像删除系统上的文件一样。因此,您应该首先了解不在那里的成员与在那里但无法访问的成员之间的区别。现在假设所有继承都是公开进行的。然后,基类的所有公共成员在派生类中都是公共的,受保护的成员是受保护的,而私有成员是不可访问的。它们不可访问且并非不存在,因为基类中的受保护和公共部分中可能存在一些访问基类私有成员的成员函数。因此,我们需要 base 的所有私有成员,这些成员被 base 的公共和受保护成员函数访问,以实现它们的功能。由于我们无法以简单的方式确定哪个成员函数需要哪个成员,我们在派生类中包含基类的所有私有成员。所有这一切仅仅意味着在派生类中,私有成员只能通过基类的成员函数进行修改。

Note: every private member has to be accessed, directly or indirectly [through another private member function which in turn is called by a public/protected member function] by a public/protected meber function, else it has no use.

注意:每个私有成员都必须被公共/受保护的成员函数直接或间接[通过另一个私有成员函数被公共/受保护的成员函数调用] 访问,否则它没有用。

So, we know till now that a private member variable of base class has its use in derived class i.e. for the functionality of its public/protected member functions. But they can't be accessed directly in base class.

所以,到目前为止,我们知道基类的私有成员变量在派生类中有其用途,即用于其公共/受保护成员函数的功能。但是它们不能在基类中直接访问。

Now, we turn our attention to private/public inheritance. For public inheritance, it means that all the accessible members of base class (that is, the public and protected members) can not be at a level more permissive than public. Since, public is the most permissive level, public and protected members remain public. But at protected and private inheritance, both become protected and private in the derived class, respectively. Inthe latter case, since all these members are private, they can't be accessed further in the hierarchy chain, but can be accessed by the given derived class all the same.

现在,我们将注意力转向私有/公共继承。对于公共继承,这意味着基类的所有可访问成员(即公共成员和受保护成员)都不能处于比公共更宽松的级别。由于 public 是最宽松的级别,因此 public 和受保护的成员仍然是 public。但是在受保护和私有继承中,它们在派生类中分别变为受保护和私有。在后一种情况下,由于所有这些成员都是私有的,因此无法在层次结构链中进一步访问它们,但可以由给定的派生类访问。

Thus, the level of each base class member in derived class is the lesser of their level in derived class () and the type of inheritance (public/protected/private).

因此,派生类中每个基类成员的级别是它们在派生类中的级别()和继承类型(公共/受保护/私有)中的较小者。

Same concept applies to the functions outside the class. For them private and protected members are inaccessible but they do exist and can be accessed by the public member functions.

相同的概念适用于类外的函数。对于他们来说,私有成员和受保护成员是不可访问的,但它们确实存在并且可以被公共成员函数访问。

And taking your case as a final example, setMyvariable()and getMyVariable()can access myVariablein the derived class. But no function specified in derived class can access myVariable. Modifying your class:

并以您的情况作为最后一个示例,setMyvariable()并且getMyVariable()可以myVariable在派生类中访问。但是派生类中指定的任何函数都不能访问myVariable. 修改你的类:

class myClass
{
public:
  void setMyVariable();
  int getMyVariable();
private:
  int myVariable;
};

class yourClass : public myClass
{
public:
  // void yourFunction() { myVariable = 1; }
  /*Removing comment creates error; derived class functions can't access myVariable*/
};

Further: you can add exceptions to the type of inheritance too e.g. a private inheritance except a member made public in derived class. But that is another question altogether.

此外:您也可以向继承类型添加例外,例如私有继承,除了派生类中公开的成员。但这完全是另一个问题。

回答by Oliver Charlesworth

You never call myObject.setMyVariable(), so myObject.getMyVariable()will not return 15.

你从不调用myObject.setMyVariable(),所以myObject.getMyVariable()不会返回 15。

privatedoes not imply static.

private并不意味着static

回答by M.M

After:

后:

class yourClass : public myClass {};

there is still only one member variable. But there are two ways of accessing it by name: myClass::myVariable, and yourClass::myVariable.

仍然只有一个成员变量。但是有两种按名称访问它的方法:myClass::myVariable, 和yourClass::myVariable

In these expressions, the class name is known as the naming class. The second key thing to understand is that access rights apply to the combination of naming class and member name; not just to the member name and not to the variable itself.

在这些表达式中,类名被称为命名类。第二个要理解的关键是访问权限适用于命名类和成员名的组合;不仅仅是成员名称,而不是变量本身。

If a member is mentioned without explicitly having the naming class present, then the naming class is inferred from the type of the expression on the left of the .or ->that named the member (with this->being implied if there is no such expression).

如果一个成员在没有明确地具有本命名类提到的,则命名类是从表达式的类型推断出在左侧的.->该指定的构件(与this->如果不存在这样的表达被隐含)。

Furthermore, there are really four possible types of access: public, protected, private, and no access. You can't declare a member as having no access, but that situation arises when a private member is inherited.

此外,还有一些真正的四种可能的访问类型:publicprotectedprivate,和不能访问。您不能将成员声明为没有访问权限,但是在继承私有成员时会出现这种情况。



Applying all this theory to your example:

将所有这些理论应用于您的示例:

  • The name myClass::myVariableis private.
  • The name yourClass::myVariableis no access.
  • 名字myClass::myVariableprivate
  • 名称yourClass::myVariable没有访问权限

To reiterate, there is only actually one variable, but it may be named in two different ways, and the access rights differ depending on which name is used.

重申一下,实际上只有一个变量,但它可能以两种不同的方式命名,访问权限因使用的名称而异。



Finally, back to your original example. myObjectand yourObjectare different objects. I think what you intended to write, or what you are mentally imagining is actually this situation:

最后,回到你最初的例子。myObject并且yourObject是不同的对象。我想你本来打算写的,或者你脑子里想象的其实是这样的情况:

yourClass yourObject;
myClass& myObject = yourObject;
//    ^^^

which means myObjectnames the base class part of yourObject. Then after:

这意味着myObject命名yourObject. 然后:

yourObject.setMyVariable();

the variable is set to 15, and so

变量设置为15,所以

std::cout << myObject.getMyVariable() << std::endl;

would output 15because there is indeed only one variable.

会输出,15因为确实只有一个变量。

回答by Anurag

This may help

这可能有帮助

#include<iostream>
using namespace std;

class A
{
int b;  
};

class B : private A
{

};

int main()
{
C obj;
cout<<sizeof(obj);  
return 0;
}