記事はあなたに継承を理解させる。
C ++の継承
序文
世界のすべてに継承システムがあり、人や動物など、親クラスの特定の特性を多かれ少なかれ継承します。次に、コードにもこの特性があります。見てみましょう。
ヒント:この記事の内容は次のとおりです。
1.継承
継承メカニズムは、コードを再利用可能にするためのオブジェクト指向プログラミングの最も重要な手段であり、プログラマーがクラスの元の特性を維持しながら関数を拡張および拡張できるため、派生クラスと呼ばれる新しいクラスを生成できます。継承は、オブジェクト指向プログラミングの階層構造を示し、単純なものから複雑なものまでの認知プロセスを具体化します。以前、私たちが触れた再利用はすべて関数の再利用であり、継承はクラス設計レベルの再利用でした。。
1.継承の定義
下の写真を見てみましょう。
私たちはコードを見ています
class Base
{
public:
void fun()
{
cout << "Base::fun()" << endl;
}
};
// 子类 父类
class D :public Base // 继承
{
public:
void show()
{
cout << "D::shoe()" << endl;
}
};
void main()
{
D d;
d.show();
d.fun();// 子类可以访问父类的信息
}
2.継承とアクセス修飾子
3.基本クラスと派生クラスオブジェクトの代入変換
派生クラスオブジェクトは、基本クラスオブジェクト/基本クラスポインタ/基本クラス参照に割り当てることができます。ここにスライスまたはカッティングと呼ばれる画像があります。その意味するところは、派生クラスの親クラスを切り取り、それを過去に割り当てることです。 基本クラスオブジェクトを派生クラスオブジェクトに割り当てることはできません意思就是子类可以给父类赋值,父类不能给子类赋值
コードを 見てみましょう(コードには詳細なコメントがあります)
class Person
{
public:
void Print()
{
cout << "name" << _name << endl;
cout << "age:" << _age << endl;
}
protected:
string _name = "peter"; // 姓名
int _age = 18; // 年龄
};
class Teacher : public Person
{
protected:
int _stuid; // 学号
};
void main()
{
Teacher tcher; //首先他有一个 _name _age _stuid 成员
Person per; // _name _age 成员
// 因为tcher 中包含有per的所有成员 所以子类就可以给父类赋值 而父类不可以给子类赋值
//所以我们将子类就可以给父类赋值的这种现象叫 对象的切片
}
4.継承の範囲
- 継承システムでは、基本クラスと派生クラスは独立したスコープを持っています。
- サブクラスと親クラスに同じ名前のメンバーがあります。サブクラスのメンバーは、同じ名前のメンバーへの親クラスの直接アクセスをブロックします。この状況は、非表示または再定義と呼ばれます。(サブクラスメンバー関数では、基本クラス::基本クラスメンバーの表示アクセスを使用できます)
- メンバー関数の非表示の場合は、関数名のみが非表示と同じであることに注意してください。
- 実際には、継承システムで同じ名前のメンバーを定義しないことが最善であることに注意してください。
同じ名前で隠されているもの、コードを見てみましょう
class Base
{
public:
void fun()
{
cout << "Base::fun()" << endl;
}
};
// 子类 父类
class D :public Base // 继承
{
public:
void fun()
{
cout << "D::fun()" << endl;
}
void show()
{
cout << "D::shoe()" << endl;
}
};
void main()
{
D d;
Base *pb = &d;
pb->fun();// 只能访问子类中父类所有的fun函数
d.fun(); // 只能访问子类自己的fun函数
}
上記のコードから、サブクラスが独自のfun関数にアクセスしていることがわかります。元々、サブクラスは親クラスのfun関数にアクセスできますが、サブクラスも親クラスと同じ名前の同じ関数を持っているため、親クラスは非表示です。これは同じ名前で非表示と呼ばれます
これは、子供が家を持っていない場合は父親の家に住むことができますが、子供が家を持っている場合は親の家に住むことができず、自分の家に住む必要があることと同じです。
5.派生クラスのデフォルトのメンバー関数
- 派生クラスのコンストラクターは、基本クラスのコンストラクターを呼び出して、基本クラスのメンバーのその部分を初期化する必要があります。基本クラスにデフォルトのコンストラクターがない場合は、派生クラスのコンストラクターの初期化リストの段階で呼び出しを表示する必要があります。
- 派生クラスのコピーコンストラクターは、基本クラスのコピーコンストラクターを呼び出して、基本クラスのコピー初期化を完了する必要があります。
- 基本クラスのコピーを完了するには、派生クラスのOperator =を基本クラスのoperator =と呼ぶ必要があります。
- 派生クラスのデストラクタは、基本クラスのデストラクタを自動的に呼び出して、呼び出された後に基本クラスのメンバーをクリーンアップします。これは、派生クラスオブジェクトが最初に派生クラスメンバーをクリーンアップし、次に基本クラスメンバーの順序をクリーンアップすることを保証する方法であるためです。
- 派生クラスオブジェクトの初期化は、最初に基本クラス構造を呼び出し、次に派生クラス構造を呼び出します。
- 派生クラスオブジェクトの破棄のクリーンアップでは、最初に派生クラスの破棄を呼び出してから、基本クラスの破棄を調整します
このクラスの6つのデフォルトのメンバー関数は、コンストラクター、コピーコンストラクター、デストラクタ、代入演算子のオーバーロード、アドレス演算子のオーバーロード、およびconstで変更されたアドレス演算子のオーバーロードです。
継承関係では、6つのデフォルトコンストラクターが派生クラスで明示的に定義されていない場合、コンパイラシステムはデフォルトでこれらの6つのメンバー関数を合成します。
見てみるためにコードを書いてみましょう(コードには詳細なコメントがあります)
class Base
{
public:
Base()
{
cout << "Base::Base()" << endl;
}
Base(const Base &b)// 拷贝构造
{
cout << "Base::Base(const Base &)" << endl;
m_b = b.m_b;
}
Base operator=(const Base &b)//赋值语句
{
cout << "Base operator=(const Base &b)" << endl;
m_b = b.m_b;
return *this;
}
public:
void fun()
{
cout << "Base::fun()" << endl;
}
void fun(int a)
{
cout << "Base::fun(int a)" << endl;
}
private:
int m_b;
};
// 子类 父类
class D :public Base // 继承
{
public:
D() :m_b(0) // 会调用父类的构造方法 但是如果父类构造方法给一个 Base(int b):m_b(b) 就不能成功了 因为父类要求是一个有参的 所以在参数列表改为 D():m_b(0),Base(0)
{
}
public:
void fun()
{
cout << "Base::fun()" << endl;
}
void show()
{
cout << "D::shoe()" << endl;
}
private:
int m_b;
};
void main()
{
D d;
D d1 = d;// 调用的是父类的拷贝构造方法 说明我们在完成子类的拷贝构造当中首先要拷贝构造的是父类对象
D d2;
d2 = d1;
}
結果は次のとおりです。
見える:
実際、コンパイラーは最初に派生クラスのコンストラクターに入り、次に初期化リストの基本クラスのコンストラクターを呼び出し、次に戻って独自の関数本体を実行します。
6.継承と友達
友情関係を継承することはできません。つまり、基本クラスの友達は、サブクラスのプライベートメンバーと保護されたメンバーにアクセスできません。
具体的には、コードを見てみましょう(コードには詳細なコメントがあります)
//友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员 如下
class Student;
class Person;
void Display(const Person& p, const Student& s);
class Person
{
public:
friend void Display(const Person& p, const Student& s);
protected:
string _name = "cb"; // 姓名
};
class Student : public Person
{
protected:
int _stuNum = 418; // 学号
};
void Display(const Person& p, const Student& s)
{
cout << p._name << endl;
cout << s._stuNum << endl;// 之所以不能访问就是因为这仅仅是父类的友元函数 子类不能访问
// 要怎末才能访问 就只能形成自己的友元函数 在子类中在加一句friend void Display(const Person& p, const Student& s);
// 相当于爸爸的朋友不见得是儿子的朋友 儿子要操作只能自己在声明交朋友形成友元函数
}
void main()
{
Person p;
Student s;
Display(p, s);
}
上記のコードは、友達が友達と同じであることを示しています。親カテゴリの友達は必ずしも子カテゴリの友達ではありません。同じ子カテゴリの友達は必ずしも親カテゴリの友達ではありません。したがって、誰かを訪問したい場合は、誰の友達であるかを宣言する必要があります。宣言された後でのみ、そのプライベートメンバーまたは保護されたメンバーにアクセスできます。
- フレンド関係には推移性はありません。つまり、各クラスは、独自のフレンドクラスまたはフレンド関数を制御する責任があります。
- 友情関係は一方向であり、互換性はありません。クラスBがクラスAのフレンドである場合、クラスに対応する宣言があるかどうかによって、クラスAは必ずしもクラスBのフレンドであるとは限りません。
- 友情は受け継がれません。
7.継承と静的メンバー
基本クラスは静的静的メンバーを定義し、継承システム全体でそのようなメンバーは1つだけです。派生するサブクラスの数に関係なく、静的メンバーインスタンスは1つだけです。
同様に、次のようにコードを確認します。
//继承与静态成员
//基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例 。如下
class Test
{
public:
Test()
{
count++;
}
public:
int GetCount()const
{
return count;
}
//int GetCount()const
//{
// return GetOBJCount();
//}
private:
static int count;// 类的静态成员必须在类外初始化
//因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的
};
int Test::count = 0;
class D1 :public Test
{
public:
//int GetCount()const
//{
// return GetOBJCount();
//}
};
class D2 :public Test
{
public:
//int GetCount()const
//{
// return GetOBJCount();
//}
};
class D3 :public Test
{
public:
//int GetCount()const
//{
// return GetOBJCount();
//}
};
class D4 :public Test
{
public:
//int GetCount()const
//{
// return GetOBJCount();
//}
};
void main()
{
D1 d1;
cout << d1.GetCount() << endl;
D2 d2;
cout << d2.GetCount() << endl;
D3 d3;
cout << d3.GetCount() << endl;
D4 d4;
cout << d4.GetCount() << endl;
}
上記のコードを通して、見るのは難しくありません:
基本クラスは静的静的メンバーを定義し、継承システム全体でそのようなメンバーは1つだけです。派生するサブクラスの数に関係なく、静的メンバーインスタンスは1つだけです。
静的に変更されたメンバーは、クラス内でのみ宣言でき、クラス外で定義できます。その理由は、静的メンバーはオブジェクトではなくクラス全体に属しているためです。クラスで初期化すると、各オブジェクトに静的メンバーが含まれます。これは矛盾しています。 。
総括する
公的継承はis-a関係です。つまり、各派生クラスオブジェクトは基本クラスオブジェクトです。
組み合わせは持っている-関係です。BがAを結合し、各BオブジェクトにAオブジェクトがあるとします。
ここでは、ダイヤモンド継承などの複雑な問題を含む多重継承問題についても説明する必要があり ます。(後でブログクラスで詳細な紹介があります)
読んでいただきありがとうございます。エラーがあれば訂正してください。!!