12

基本的に私が知る限り、パブリックセクション、プロテクトセクション、プライベートセクションを含む基本クラスを作成すると、パブリックセクションとプロテクトセクションのそれぞれの変数/関数は、サブクラスの適切なセクション(クラスサブクラスによって定義される)に継承されます。 :プライベートベース。ベースのすべてのパブリックメンバーと保護されたメンバーを公開します。プライベートという単語をパブリックに変更すると、すべてがパブリックになり、保護に変更すると、すべてが保護されます)。

したがって、サブクラスを作成するときに、前のクラス(この場合は基本クラス)のプライベートセクションから何も受け取らない場合、これがtrueの場合、サブクラスのオブジェクトは独自のバージョンの基本クラスのプライベート変数または関数は正しいですか?

例を実行してみましょう:

#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を使用しています)。しかし、奇妙なことに、これは当てはまりません。このプログラムを実行した結果は次のようになります。150これは、実際にmyVariableを継承するだけでなく、それをいじくり回す機能もあるのだろうかと思います。明らかに、これはmyVariableの代替バージョンを何らかの形で作成しています。そうでない場合、myClassバージョンに0はありません。実際、これをすべて実行して、myVariableの2番目のコピーを編集しています。

誰かがこれをすべて私に説明してもらえますか、これは私の継承の理解を崩壊させました。

4

7 に答える 7

20

基本的に私が知る限り、パブリックセクション、プロテクトセクション、プライベートセクションを含む基本クラスを作成すると、パブリックセクションとプロテクトセクションのそれぞれの変数/関数は、サブクラスの適切なセクション(クラスサブクラスによって定義される)に継承されます。 :プライベートベース。ベースのすべてのパブリックメンバーとプライベートメンバーを取得してパブリックにします。プライベートという単語をパブリックに変更すると、すべてがパブリックになり、保護に変更すると、すべてが保護されます)。

この声明には少し混乱があります。

継承はC++のクラスと構造体に対して定義されていることを思い出してください。個々のオブジェクト(つまりインスタンス)は他のオブジェクトから継承しません。他のオブジェクトを使用してオブジェクトを構築することを合成と呼びます。

クラスが別のクラスから継承する場合、そのクラスからすべてを取得しますが、継承されたフィールドのアクセスレベルにより、継承内での使用が妨げられる場合があります。

さらに、クラスには3種類の継承があります:(privateデフォルト)、、、protectedおよびpublic。それらのそれぞれは、サブクラスによって継承されるときに、クラスのプロパティとメソッドのアクセスレベルを変更します。

アクセスレベルを次のように並べ替えると、、、、、public最もprotected保護privateされていないものから最も保護されているものへと、継承修飾子を定義して、継承されたクラスフィールドのアクセスレベルを、派生クラスで少なくとも指定されたレベルに上げることができます。クラス(つまり、クラスの継承)。

たとえば、クラスが継承修飾子を使用してBクラスから継承する場合、次のようになります。Aprotected

  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

myObjectyourObjectは2つの異なるオブジェクトです!なぜ彼らは何かを共有する必要がありますか?

そのように考えてください。継承を忘れて、とのクラスPersonがあるprivate int age;としpublic void setAge (int age) {...}ます。次に、2つのオブジェクトをインスタンス化します。

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

ビルも今35歳になると思いますか?そうじゃないでしょう?同様に、あなたmyObjectはそのデータを。と共有しませんyourObject


あなたのコメントに応えて:

クラスyourClassはから継承しmyClassます。つまり、とは両方ともyourObject独自myObjectのものを持ってmyVariableおり、後者は明らかに定義上、前者はから継承されてmyClassいます。

于 2013-01-11T02:23:22.843 に答える
6

物理的には、基本クラスのすべてのメンバー(メンバー関数を含む)がサブクラスに入ります。プライベートかどうかは関係ありません。それらを公的に/保護されて/私的に継承するかどうかは関係ありません。したがって、あなたの例では、、、およびyourClassの3つすべてが含まれています。これはすべてとても簡単ですいいですねgetMyVariable()setMyVariable()myVariable

重要なのは、どのようにそれらにアクセスできるかです。これは、システムでファイルが削除されたときのようなものです。したがって、最初に、メンバーがそこにいないことと、メンバーがそこにいるがアクセスできないことの違いを理解する必要があります。今のところ、すべての継承は公に行われていると仮定します。次に、基本クラスのすべてのパブリックメンバーは派生クラスでパブリックになり、保護されたメンバーは保護され、プライベートメンバーにはアクセスできなくなります。基本クラスのプライベートメンバーにアクセスする基本クラスの保護されたセクションとパブリックセクションにいくつかのメンバー関数が存在する可能性があるため、これらにはアクセスできず、存在しません。したがって、baseのパブリックおよび保護されたメンバー関数によってアクセスされるbaseのすべてのプライベートメンバーが、それらの機能のために必要です。どのメンバーがどのメンバーに必要かを簡単に判断する方法がないので、基本クラスのすべてのプライベートメンバーを派生クラスに含めます。これはすべて、派生クラスでは、基本クラスのメンバー関数を介してのみプライベートメンバーを変更できることを意味します。

注:すべてのプライベートメンバーは、パブリック/保護されたメンバー関数によって直接または間接的に[パブリック/保護されたメンバー関数によって呼び出される別のプライベートメンバー関数を介して]アクセスする必要があります。そうでない場合、使用できません。

したがって、これまで、基本クラスのプライベートメンバー変数は、派生クラスで、つまりパブリック/保護されたメンバー関数の機能のために使用されることがわかっています。ただし、基本クラスで直接アクセスすることはできません。

ここで、私たちは私的/公的継承に注意を向けます。パブリック継承の場合、基本クラスのすべてのアクセス可能なメンバー(つまり、パブリックメンバーと保護されたメンバー)がパブリックよりも寛容なレベルになることはできないことを意味します。パブリックは最も寛容なレベルであるため、パブリックおよび保護されたメンバーはパブリックのままです。ただし、保護された継承とプライベート継承では、派生クラスでそれぞれ保護されたプライベートになります。後者の場合、これらのメンバーはすべてプライベートであるため、階層チェーン内でそれ以上アクセスすることはできませんが、指定された派生クラスから同じようにアクセスできます。

したがって、派生クラスの各基本クラスメンバーのレベルは、派生クラス()のレベルと継承のタイプ(パブリック/保護/プライベート)のいずれか低い方になります。

同じ概念がクラス外の関数にも当てはまります。それらの場合、プライベートおよび保護されたメンバーにはアクセスできませんが、それらは存在し、パブリックメンバー関数からアクセスできます。

そして最後の例としてあなたのケースを取り上げ、派生クラスで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 {};

まだメンバー変数は1つだけです。ただし、名前でアクセスするには、、、の2つの方法がありmyClass::myVariableますyourClass::myVariable

これらの式では、クラス名はネーミングクラスと呼ばれます。理解すべき2つ目の重要な点は、アクセス権は名前付けクラスとメンバー名の組み合わせに適用されるということです。メンバー名だけでなく、変数自体にも影響しません。

ネーミングクラスが明示的に存在しない状態でメンバーが言及されている場合、ネーミングクラスは、.または->メンバーに名前が付けられた式のタイプから推測this->されます(そのような式がない場合は暗黙的に示されます)。

publicさらに、アクセスにはprotected、、、、privateおよびアクセスなしの4つのタイプがあります。メンバーにアクセス権がないことを宣言することはできませんが、そのような状況は、プライベートメンバーが継承されたときに発生します。


このすべての理論をあなたの例に適用します:

  • 名前myClass::myVariableprivateです。
  • 名前yourClass::myVariableアクセスできません

繰り返しになりますが、実際には変数は1つだけですが、2つの異なる方法で名前を付けることができ、使用する名前によってアクセス権が異なります。


最後に、元の例に戻ります。myObjectyourObjectは異なるオブジェクトです。あなたが書きたいと思っていたもの、またはあなたが精神的に想像しているものは、実際にはこの状況だと思います。

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

これはmyObject、の基本クラス部分に名前を付けることを意味しますyourObject。後で:

yourObject.setMyVariable();

変数はに設定されて15いるので、

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

15実際には変数が1つしかないため、出力されます。

于 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 に答える