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

Posted

技术标签:

【中文标题】子类真的继承私有成员变量吗?【英文标题】:Do Sub-Classes Really Inherit Private Member Variables? 【发布时间】:2012-12-25 14:10:26 【问题描述】:

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

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

我们来看一个例子:

#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.

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

谁能给我解释一下这一切,这打破了我对继承的理解。

【问题讨论】:

您能修正一下代码的缩进吗? myObject.getMyVariable() 是未定义的行为。 你永远不会打电话给myObject.setMyVariable。所以这是一个简单的编码错误;与继承无关! 我认为对于类和对象之间的区别可能有些混淆,并且误解为一旦使用继承,这种区别就会以某种方式消失。 【参考方案1】:

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

这个说法有点混乱。

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

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

此外,类有 3 种继承方式:private(默认设置)、protectedpublic。当被子类继承时,它们中的每一个都会改变类属性和方法的访问级别。

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

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

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

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

public 字段变为protectedpublic 级别提升到protected), protected 字段保持protected(相同的访问级别,所以这里没有修改), private 字段保持private(访问级别已经在修饰符之上)

【讨论】:

哇,非常感谢您的有用帖子。这完美地解释了一切! (真的谢谢大家,但这个得到了最好的答案)【参考方案2】:

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

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

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
  
;

【讨论】:

很有趣,那么您可以访问通过替代方法继承的私有成员吗?我的意思是,无论如何我可以访问 myVariable 在 yourClass 中吗?我明白你的意思,但是 getMyVariable 不会只访问基类的 myVariable 版本而不是访问 yourclass 版本吗?我读到您不能使用任何继承到子类中的私有成员变量(在您的帖子之后进行了更多研究)。 你不能在子类的实现中使用它们。当然,您可以在基类的实现中使用它们,并从外部调用基类的公共方法/访问公共字段。 对对对,但我的意思是,如何访问和修改子类继承的私有成员的版本? 私有成员只有一个版本。子类继承基类的成员,没有什么比第二个副本更好的了。在幕后,您实际访问和修改的是基类的版本。 (这意味着您的yourObject 以某种方式访问​​myObject,它们是不同的对象!) 啊,所以它类似于继承一个公共函数,你可以访问它(虽然在这种情况下不是直接的)但是你没有得到你自己的版本,除非你覆盖它? 【参考方案3】:

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

这样想:忘掉继承,假设你有一个类Personprivate int age;public void setAge (int age) ...。然后实例化两个对象:

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

你希望比尔现在也 35 岁吗?你不会的,对吧?同样,您的 myObject 不会与 yourObject 共享其数据。


回应您的评论:

yourClass 类继承自 myClass。这意味着yourObjectmyObject 都有自己的myVariable,后者显然根据定义,前者继承自myClass

【讨论】:

哦!!!!难怪,它是两个不同的对象,这就是为什么!每个对象都有自己的函数实例等。那么我的 myVariable 永远不会被继承是对的吗?我只是想澄清一下,我对继承的理解是否正确? 继承的,看 Beta 的回答! 非常感谢你的小补充,现在一切都变得有意义了。也谢谢你!【参考方案4】:

从物理上讲,基类的每个成员(包括成员函数)都进入了子类。没关系,如果他们是私人的。如果您公开/受保护/私下继承它们都没关系。所以在你的例子中,yourClass 包含所有三个getMyVariable()setMyVariable()myVariable。这一切都很简单,好吗?

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

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

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

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

因此,每个基类成员在派生类中的级别是它们在派生类中的级别()和继承类型(public/protected/private)中较小的一个。

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

以你的情况作为最后一个例子,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*/
;

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

【讨论】:

很好的答案!非常清楚并涵盖了问题的各个方面。【参考方案5】:

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

private 并不暗示static

【讨论】:

嗯,它很酷...不过我知道你的意思:) 这就是这个问题的重点,为什么yourObject.getMyVariable返回15?这意味着有两个 myVariable 实例,否则无论您使用哪个对象设置/获取它都会返回 15。显然有两个 myVariables,这就是问题所在。【参考方案6】:

之后:

class yourClass : public myClass ;

仍然只有一个成员变量。但是有两种通过名称访问它的方法:myClass::myVariableyourClass::myVariable

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

如果在没有明确存在命名类的情况下提及成员,则从命名该成员的 .-&gt; 左侧的表达式类型推断命名类(this-&gt; 是如果没有这样的表达式,则隐含)。

此外,实际上有四种可能的访问类型:publicprotectedprivate无访问权限。您不能将成员声明为无访问权,但是当私有成员被继承时就会出现这种情况。


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

名字myClass::myVariableprivate。 名字yourClass::myVariable无权访问

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


最后,回到你原来的例子。 myObjectyourObject 是不同的对象。我想你打算写的,或者你心里想象的,其实就是这种情况:

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

这意味着myObject 命名yourObject 的基类部分。然后:

yourObject.setMyVariable();

变量设置为15,以此类推

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

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

【讨论】:

【参考方案7】:

这可能会有所帮助

#include<iostream>
using namespace std;

class A

int b;  
;

class B : private A


;

int main()

C obj;
cout<<sizeof(obj);  
return 0;

【讨论】:

以上是关于子类真的继承私有成员变量吗?的主要内容,如果未能解决你的问题,请参考以下文章

Java中类变量可以被继承吗

子类从父类继承过来的方法可以操作子类自己定义的成员变量吗

子类会在后台包含来自超类的私有方法和成员变量吗? [复制]

继承的基本概念: Java不支持多继承,也就是说子类至多只能有一个父类。 子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法。 子类中定义的成员变量和父类中

子类能继承父类的哪些变量和方法

子类可以继承父类的一切方法,成员变量,甚至是私有的,但是却不能够访问这些私有的成员变量和方法