基本的に私が知る限り、パブリックセクション、プロテクトセクション、プライベートセクションを含む基本クラスを作成すると、パブリックセクションとプロテクトセクションのそれぞれの変数/関数は、サブクラスの適切なセクション(クラスサブクラスによって定義される)に継承されます。 :プライベートベース。ベースのすべてのパブリックメンバーと保護されたメンバーを取得してパブリックにします。プライベートからパブリックにWordを変更すると、すべてがパブリックになり、保護に変更すると、すべてが保護されます)。
したがって、サブクラスを作成するときに、前のクラス(この場合は基本クラス)のプライベートセクションから何も受け取らないので、これが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.
}
さて、理論的には、これは次のように出力されます。1515これにより、常にmyClassバージョンの関数を使用します(したがって、myClass myVariableを使用します)。しかし、奇妙なことに、これは当てはまりません。このプログラムを実行した結果は次のようになります。150これは、実際にはmyVariableを継承するだけでなく、それをいじくり回す機能もあるのだろうかと思います。明らかに、これはmyVariableの代替バージョンを何らかの方法で作成しています。そうでない場合、myClassバージョンに0はありません。実際、これをすべて実行して、myVariableの2番目のコピーを編集しています。
誰かがこれをすべて私に説明してもらえますか、これは私の相続の理解を崩壊させました。
基本的に私が知る限り、パブリックセクション、プロテクトセクション、プライベートセクションを含む基本クラスを作成すると、パブリックセクションとプロテクトセクションのそれぞれの変数/関数は、サブクラスの適切なセクション(クラスサブクラスによって定義される)に継承されます。 :プライベートベース。ベースのすべてのパブリックメンバーとプライベートメンバーを取得してパブリックにします。Wordをプライベートからパブリックに変更すると、すべてがパブリックになり、保護に変更すると、すべてが保護されます)。
この声明には少し混乱があります。
継承はC++のクラスと構造体に対して定義されていることを思い出してください。個々のオブジェクト(つまりインスタンス)は他のオブジェクトから継承しません。他のオブジェクトを使用してオブジェクトを構築することをcompositionと呼びます。
クラスが別のクラスから継承する場合、そのクラスからすべてを取得しますが、継承されたフィールドのアクセスレベルにより、継承内での使用が妨げられる場合があります。
さらに、クラスには、private
(デフォルト)、protected
、およびpublic
の3種類の継承があります。それらのそれぞれは、サブクラスによって継承されるときに、クラスのプロパティとメソッドのアクセスレベルを変更します。
public
、protected
、private
のようにアクセスレベルを順序付けすると、保護が最も低いものから最も保護されたものへと、継承修飾子を上げるように定義できます。継承されたクラスフィールドのアクセスレベルは、派生クラス(つまり、継承されたクラス)で少なくとも指定されたレベルになります。
たとえば、クラスB
がクラスA
からprotected
継承修飾子を使用して継承する場合:
class B : protected A { /* ... */ };
その場合、A
のすべてのフィールドは少なくともprotected
のB
レベルになります。
public
フィールドはprotected
になります(public
レベルはprotected
に上げられます)、protected
フィールドはprotected
のままです(同じアクセスレベルなので、ここでは変更しません)、private
フィールドはprivate
のままです(アクセスレベルはすでに修飾子を上回っています)「サブクラスを作成すると、[基本クラス]のプライベートセクションから何も受信しません。これが当てはまる場合、サブクラスのオブジェクトは、ベースから独自のバージョンのプライベート変数または関数を持つべきではありません。クラス、正しいですか?」
いいえ。派生クラスは、プライベートクラスを含む基本クラスのすべてのメンバーを継承します。継承されたクラスのオブジェクトhasこれらのプライベートメンバーですが、それらへの直接アクセスはありません。基本クラスのパブリックメンバーにアクセスでき、それらのメンバーにアクセスできますが、そのメンバー(派生クラス)には、そのようなアクセス権を持つ新しいメンバー関数がない場合があります。
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
}
};
myObject
とyourObject
は2つの異なるオブジェクトです!なぜ彼らは何かを共有する必要がありますか?
そのように考えてください。継承を忘れて、_private int age;
_とpublic void setAge (int age) {...}
を持つクラスPerson
があるとします。次に、2つのオブジェクトをインスタンス化します。
_Person bob;
Person bill;
bob.setAge(35);
_
ビルも今35歳になると思いますか?そうじゃないでしょう?同様に、myObject
はそのデータをyourObject
と共有しません。
あなたのコメントに応えて:
クラスyourClass
はmyClass
から継承します。つまり、yourObject
とmyObject
の両方に独自のmyVariable
があり、後者は明らかに定義上、前者はmyClass
から継承されています。
物理的には、基本クラスのすべてのメンバー(メンバー関数を含む)がサブクラスに入ります。プライベートかどうかは関係ありません。あなたがそれらを公的に/保護された-ly/privatelyに継承するかどうかは関係ありません。したがって、この例では、yourClass
にはgetMyVariable()
、setMyVariable()
、およびmyVariable
の3つすべてが含まれています。これはすべてとても簡単ですいいですね
重要なのは、どのようにそれらにアクセスできるかです。これは、システムでファイルが削除されたときのようなものです。したがって、最初に、メンバーがそこにいないことと、メンバーがそこにいるがアクセスできないことの違いを理解する必要があります。今のところ、すべての継承は公に行われていると仮定します。次に、基本クラスのすべてのパブリックメンバーは派生クラスでパブリックになり、保護されたメンバーは保護され、プライベートメンバーにはアクセスできなくなります。基本クラスのプライベートメンバーにアクセスする基本クラスの保護されたセクションとパブリックセクションにいくつかのメンバー関数が存在する可能性があるため、これらにはアクセスできず、存在しません。したがって、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*/
};
さらに:継承のタイプに例外を追加することもできます。派生クラスで公開されたメンバーを除くプライベート継承。しかし、それはまったく別の質問です。
myObject.setMyVariable()
を呼び出すことはないため、myObject.getMyVariable()
は15を返しません。
private
はstatic
を意味するものではありません。
後:
class yourClass : public myClass {};
まだメンバー変数は1つだけです。ただし、名前でアクセスするには、myClass::myVariable
とyourClass::myVariable
の2つの方法があります。
これらの式では、クラス名は名前付けクラスとして知られています。理解すべき2番目の重要なことは、アクセス権は名前付けクラスとメンバー名の組み合わせに適用されます;メンバー名だけでなく、変数自体にも影響しません。
ネーミングクラスが明示的に存在せずにメンバーが言及されている場合、ネーミングクラスは、メンバーに名前を付けた.
または->
の左側の式のタイプから推測されます(そのような式がない場合はthis->
が暗黙指定されます)。
さらに、実際には4つの可能なアクセスタイプがあります:public
、protected
、private
、およびアクセスなし。メンバーにアクセスなしがあると宣言することはできませんが、プライベートメンバーが継承されるとその状況が発生します。
このすべての理論をあなたの例に適用する:
myClass::myVariable
という名前はprivate
です。yourClass::myVariable
はアクセスなしです。繰り返しになりますが、実際には変数は1つだけですが、2つの異なる方法で名前を付けることができ、使用する名前によってアクセス権が異なります。
最後に、元の例に戻ります。 myObject
とyourObject
は異なるオブジェクトです。あなたが書くつもりだったもの、またはあなたが精神的に想像しているものは、実際にはこの状況だと思います。
yourClass yourObject;
myClass& myObject = yourObject;
// ^^^
これは、myObject
がyourObject
の基本クラス部分に名前を付けることを意味します。後で:
yourObject.setMyVariable();
変数は15
に設定されているため、
std::cout << myObject.getMyVariable() << std::endl;
実際には変数が1つしかないため、15
を出力します。