子类是否真的继承了私有成员变量?

时间:2013-01-11 02:16:20

标签: c++ inheritance private members

基本上据我所知,当你创建一个带有public,protected和private部分的基类以及每个public和protected部分中的变量/函数时,它们将被继承到子类的相应部分(已定义)按类子类:private base,它将接受所有公共和受保护的base成员并将它们公开,将private更改为public将它们全部公开并将其更改为protected将它们全部置于保护状态。)

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

让我们来看一个例子:

#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的第二个副本。

有人可以向我解释这一切,这已经撕裂了我对继承的理解。

7 个答案:

答案 0 :(得分:20)

  

基本上据我所知,当你创建一个带有public,protected和private部分的基类以及每个public和protected部分中的变量/函数时,它们将被继承到子类的相应部分(已定义)按类子类:private base,它将接受base的所有公共和私有成员并将它们公开,将private更改为public将它们全部公开并将其更改为protected将它们全部置于保护状态。)

这句话中有点混乱。

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

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

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

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

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

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

然后来自A的所有字段在protected中至少具有B级别:

  • public字段变为protectedpublic级别提升为protected),
  • protected字段保留protected(访问级别相同,因此不需要修改),
  • private字段保留private(访问级别已高于修饰符)

答案 1 :(得分:9)

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

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

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

答案 2 :(得分:7)

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

以这种方式思考:忘掉继承,假设你有Personprivate int age;的班级public void setAge (int age) {...}。然后,您实例化两个对象:

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

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


回应你的评论:

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

答案 3 :(得分:6)

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

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

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

因此,我们知道基类的私有成员变量在派生类中的使用,即其公共/受保护成员函数的功能。但是它们不能直接在基类中访问。

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

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

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

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

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

答案 4 :(得分:5)

您永远不会致电myObject.setMyVariable(),因此myObject.getMyVariable()不会返回15。

private并不意味着static

答案 5 :(得分:0)

后:

class yourClass : public myClass {};

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

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

如果提到某个成员而没有明确地存在命名类,则从命名该成员的.->左侧的表达式类型推断出命名类(带有如果没有这样的表达,则隐含this->

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

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

  • 名称myClass::myVariableprivate
  • 名称yourClass::myVariable 无权访问

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

最后,回到原来的例子。 myObjectyourObject是不同的对象。我认为你打算写的,或者你在想象的是这种情况:

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

表示myObject命名yourObject的基类部分。然后:

yourObject.setMyVariable();

变量设置为15,因此

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

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

答案 6 :(得分:-2)

这可能会有所帮助

#include<iostream>
using namespace std;

class A
{
int b;  
};

class B : private A
{

};

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