継承 継承
C++ での再利用性
親クラスの基本クラス
継承派生
サブクラスの派生クラス
C++ は、継承を通じてコードの再利用性を実現します。
#include <iostream>
using namespace std;
class Human //父类 共性
{
public:
void eat(string food)
{
cout<<"i am eating"<<food<<endl;
}
};
//public 继承方式
class Teacher:public Human // 子类在父类的基础上增加了新的功能,体现的是个性
{
//访问权限
public:
void tech(string course)
{
cout<<"i am a teacher teach "<<course<<endl;
}
};
class Student:public Human
{
public:
void study(string course)
{
cout<<"i am a student learning "<<course<<endl;
}
};
int main()
{
Teacher t;
t.tech("ttttt");
Student s;
s.eat("aaa");
s.study("c++");
return 0;
}
構成は集合関係です
相続関係に属する
パブリック継承メソッドは、サブクラスのメンバーのアクセス方法には影響しませんが、サブクラスの親クラスのメンバーのアクセス方法には影響します。
親クラスのパブプロプリ
サブクラス public は public protected inaccess を継承します
1. デストラクターとコンストラクターを除く、継承後のすべてを受け入れます。基本クラスを使用すると派生クラスのメンバーが冗長になるため、蓄積を設計する必要があります。
2. 派生クラスには独自の個性があり、それが派生クラスを意味のあるものにします。
学生.h
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
using namespace std;
class Student
{
public:
Student(string sn, int ia, float fs)
{
}
void dis();
private:
string name;
int age;
float score;
};
#endif //STUDENT_H
学生.cpp
#include "student.h"
#include <iostream>
Student::Student(string sn, int ia, float fs)
:name(sn),age(ia),score(fs)
{
}
void Student::dis()
{
cout<<"name: "<<name<<endl;
cout<<"age: "<<age<<endl;
cout<<"score: "<<score<<endl;
}
main.cpp
#include <iostream>
#include "student.h"
#include "gradient.h"
#include "doctor.h"
using namespace std;
int main()
{
Student s("aa", 30, 100);
s.dis();
cout<<"----------"<<endl;
Graduate g("ggg", 50, 90, 1000);
g.print();
Doctor d("ddd", 23, 200, 5000, "doc");
d.dump();
return 0;
}
卒業生.h
#ifndef GRADUATE_H
#define GRADUATE_H
#include "student.h"
class Graduate:public Student
{
public:
Graduate(string sn, int ia, float fs, double ds);
void print();
private:
double salary;
};
#endif //GRADUATE_H
グラデーション.cpp
#include "gradient.h"
Gradient::Gradient(string sn, int ia, float fs, double ds)
:Student(sn, ia, fs),salary(ds)
{
//inaccess
// name = sn;
// age = ia;
// score = fs;
}
void Gradient::print()
{
dis(); // name age score 不可见,dis()可用
cout<<"salary: "<<salary<<endl;
}
親クラスに標準構成、オーバーロード、またはデフォルトがある場合は、デフォルトを含めます。
サブクラスは親クラスのコンストラクターを明示的に呼び出す必要はありません。
ドクター・h
#ifndef DOCTOR_H
#define DOCTOR_H
#include "gradient.h"
class Doctor:public Gradient
{
public:
Doctor(string sn, int ia, float fs, double ds, string st);
void dump()
{
print();
cout<<"title: "<<title<<endl;
}
private:
string title;
};
#endif //DOCTOR_H
ドクター.cpp
#include "doctor.h"
Doctor::Doctor(string sn, int ia, float fs, double ds, string st)
:Gradient(sn,ia,fs,ds),title(st)
{
}
サブクラスは、親クラスの親クラスではなく、親クラスに対してのみ責任を負う必要があります。
クラス int age のサブオブジェクト、浮動小数点給与
初期化順序:親クラスの初期化(親クラスの親クラスの初期化)、クラスオブジェクトの初期化、サブクラスの初期化
サブクラスがコピー構築を実装していない場合、親クラスのコピー コンストラクターが (実装されているかどうかに関係なく) 呼び出されます。
サブクラスがコピー構築を実装したら、親クラスのコピー コンストラクターを明示的に呼び出す必要があります。
#ifndef STUDENT_H
#define STUDENT_H
class Student
{
public:
Student(string sn, int ia, float fs):
void dis();
Student(const Student& another); // 构造器
Student & operator = (const Student & another);
private:
string name;
int age;
float score;
};
#endif
#include "student.h"
#include <iostream>
using namespace std;
Student::Student(string sn, int ia, float fs)
:name(sn),age(ia),score(fs)
{
}
void Student::dis()
{
cout<<"name: "<<name<<endl;
cout<<"age: "<<age<<endl;
cout<<"score: "<<score<<endl;
}
//定义构造器
Student::Student(const Student& another)
{
this->name = another.name;
this->age = another.age;
this->score= another.score;
}
Student & Student::operator = (const Student & another)
{
if(this == &another)
return *this;
this->name = another.name;
this->age = another.age;
this->score = another.score;
return *this;
}
#ifndef GRADIENT_H
#define GRADIENT_H
#include "student.h"
class Gradient
{
public:
Gradient(string sn, int ia, float fs, double ds);
void print();
Gradient(const & another); // 构造器
Gradient & another = (const Gradient & another);
private:
double salary;
};
#endif
#include "gradient.h"
#include <iostream>
using namespace std;
Gradient::Gradient(string sn, int ia, float fs, double ds)
:Student(sn, ia, fs),salary(ds)
{
}
void Gradient::print()
{
dis();
cout<<"salary: "<<salary<<endl;
}
Gradient::Gradient(const Gradient& another)
:Student(another),salary(another.salary)
{
// Student(another); // 赋值兼容(子类对象(引用或指针),可以赋值给父类(引用或指针))
// this->salary = another.salary;
}
Gradient & Gradient::operator = (const Gradient & another)
{
}
#include <iostream>
#include "student.h"
#include "gradient.h"
using namespace std;
int main()
{
Student s("aa", 200, 100);
s.dis();
cout<<"---------"<<endl;
Gradinet g("gg", 100, 500);
g.print();
return 0;
}
代入オーバーロードがサブクラスに実装されていない場合、親クラスの代入オーバーロードが呼び出されます。
サブクラスが代入オーバーロードを実装すると、親クラスの代入オーバーロードを積極的に呼び出すことはなくなります。
サブクラスでは、親クラスと同じ名前のメンバーがシャドウされます。
overload オーバーロード: 同じスコープ、同じ関数名、異なるパラメータ リスト (数値、型、順序) が発生することを期待します。
シャドウ カバレッジ: 親クラスと子クラスでは、関数名が同じである限りシャドウが構成されますが、これは予期されていません。
継承
メンバー/継承 | 公共 | 保護された | プライベート |
公共 | 公共 | 保護された | プライベート |
保護された | 保護された | 保護された | アクセスできない |
プライベート | アクセスできない | アクセスできない | アクセスできない |
クラス内の private protected public はアクセス権に影響します
継承では、プライベートはサブクラスの親クラスのメンバーのパブリック アクセス権を保護します。
1. サブクラス内 2. サブクラス オブジェクト内
バーチャル
多数の親クラスから共通因子を抽出し、同じクラスのメンバーを祖父母クラスにそれぞれ言及し、親クラスは祖父母クラスを仮想継承し、サブクラスは親クラスを通常継承するようにします。このとき、冗長な情報はありません。サブクラスにもアクセスできるので便利です。
#include <iostream>
using namespace std;
class M
{
public:
M(int m):a(m){}
protected:
int a;
};
class A:virtual public M
{
public:
A(int i):M(i){}
};
class B:virtual public M
{
public:
B(int j):M(j){}
};
class C:public A, public B
{
public:
C(int m):A(m), B(m), M(m){}
void func()
{
cout<<a<<endl;
}
};
int main()
{
C c(100);
c.func();
return 0;
}
仮想継承
クラスA: 仮想パブリックM
仮想基本クラスには設計と抽象化が必要であり、仮想継承は継承の拡張です。
class A
{
A(int i)
{}
};
class B:virtual public A
{
B(int n):A(n){}
};
class C:virtual public A
{
C(int n):A(n){}
};
class D:public B, public C
{
D(int n)
:A(n), B(n), C(n)
{}
};