12

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

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

让我们来看一个例子:

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

有人可以向我解释这一切吗,这打破了我对继承的理解。

4

7 回答 7

20

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

这个说法有点混乱。

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

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

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

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

例如,如果类BA具有protected继承修饰符的类继承:

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

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

  • public字段变为protectedpublic级别提升到protected),
  • protected字段保持protected不变(相同的访问级别,所以这里没有修改),
  • private字段保持private(访问级别已经在修饰符之上)
于 2013-01-11T03:03:10.573 回答
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
  }
};
于 2013-01-11T02:35:48.103 回答
7

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

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

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

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


回应您的评论:

该类yourClass继承自myClass. 这意味着两者yourObject都有myObject自己的myVariable,后者显然根据定义,前者继承自myClass

于 2013-01-11T02:23:22.843 回答
6

从物理上讲,基类的每个成员(包括成员函数)都进入了子类。没关系,如果他们是私人的。如果您公开/受保护/私下继承它们都没关系。所以在你的例子中,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*/
};

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

于 2013-01-11T03:17:59.230 回答
5

你从不打电话myObject.setMyVariable(),所以myObject.getMyVariable()不会返回 15。

private并不意味着static

于 2013-01-11T02:21:13.810 回答
0

后:

class yourClass : public myClass {};

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

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

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

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


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

  • 名字myClass::myVariableprivate
  • 这个名字yourClass::myVariable没有权限的。

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


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

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

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

yourObject.setMyVariable();

变量设置为15,所以

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

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

于 2016-09-01T08:12:46.997 回答
-2

这可能会有所帮助

#include<iostream>
using namespace std;

class A
{
int b;  
};

class B : private A
{

};

int main()
{
C obj;
cout<<sizeof(obj);  
return 0;
}
于 2017-09-12T04:29:08.620 回答