由于C++的類沒學好脱衙。這是在另一個班學習的筆記
一、面向對象的三大特征
????封裝例驹、繼承和多態(tài)
二、類之間的繼承
【1】訪問權限
????public:類中退唠、子類和類外都可以訪問
????private:類中可以訪問鹃锈,類外和子類中都不能訪問
????protected:類中和子類可以訪問,類外不能訪問
【2】繼承
????繼承指的是瞧预,基于已有類屎债,創(chuàng)建出新類的過程。
????基類和派生類
????父類和子類
【3】繼承的作用
? ? ? 能提高代碼的復用性垢油,父類/基類中原有的內(nèi)容盆驹,在子類/派生類中無需再定義,直接使用即可
繼承是實現(xiàn)多態(tài)的前提
【4】繼承的格式
????已有class A滩愁,要創(chuàng)建一個class B繼承自A
????class B:權限 A? ----->創(chuàng)建一個B類躯喇,用特定的權限繼承方式繼承自A
????A類可以被稱為父類、基類
????B類可以被稱為子類、派生類
????class B:public A{}? ---->B類公有繼承A類
????class B:private A{}? ---->B類私有繼承A類
????class B:protected A{}? ---->B類受保護的繼承A類
三種繼承權限? ? ? ? ? ? ? ? ? ?
????父類中訪問權限? ??
? ? ? ?public|protected|private? ? ? public|protected|private? ? ? public|protected|private?
????繼承方式? ? ? ? ? ? ? ?
?????????????????????????public? ? ? ? ? ? ? ? ? ? ? ????????? private? ? ? ? ? ? ? ? ? ? ? ? ? protected? ? ? ? ? ?
子類中訪問權限? ??
????????public|protected|不能訪問? ? ? private|private|不能訪問? ? ? ? protected|protected|不能訪問
【5】子類對父類中成員的繼承
子類會繼承父類中的所有成員廉丽,包括私有成員
類之間的繼承關系倦微,可以理解為是包含關系
子類中從父類繼承的成員,先存放正压,放在首地址欣福,父類的指針/引用可以指向子類的對象
父類的指針,可以訪問的空間焦履,只有父類本身的內(nèi)容拓劝,子類的指針可以訪問的空間包含父類繼承的和子類拓展的
【6】子類中存在和父類同名成員時
????通過子類對象默認訪問的是,子類的成員
????如果想要訪問父類的成員嘉裤,使用類名加上域標識符可以訪問父類中的內(nèi)容
????或者也可以通過父類的指針指向子類對象郑临,再來訪問
三、繼承中特殊的成員函數(shù)
這四個成員函數(shù)都不會被繼承
【1】構造函數(shù)
父類中的構造函數(shù)不會被繼承
實例化子類對象時价脾,先調(diào)用父類中的構造函數(shù)恬总,再調(diào)用子類中的構造函數(shù)
如果父類中只有有參構造蔚龙,子類必須在構造函數(shù)的初始化列表中顯性的調(diào)用父類的有參構造
【2】析構函數(shù)
父類中的析構函數(shù)不會被子類繼承
先析構子類,再析構父類
有指針成員的情況:如果父類中有指針成員,需要在父類的析構函數(shù)中手動釋放堆區(qū)的空間狼犯;如果子類中有指針成員,需要在子類的析構函數(shù)中手動釋放堆區(qū)的空間
父類的析構函數(shù)显沈,不需要再子類中手動調(diào)用积蜻,系統(tǒng)會自動調(diào)用析構函數(shù)
【3】拷貝構造函數(shù)
申請空間并初始化
如果父類中有指針成員,繼承時會不會涉及到深淺拷貝問題骇笔?會
父類的拷貝構造不會被繼承
如果父類中有指針成員省店,需要顯性寫出父類的深拷貝函數(shù);如果指針成員在子類中九顯性寫出子類的深拷貝函數(shù)
子類的拷貝構造需要顯性調(diào)用父類的拷貝構造笨触,直接傳子類的對象
【4】拷貝賦值函數(shù)
拷貝賦值函數(shù)也涉及到深淺拷貝問題
拷貝賦值函數(shù)也不會被繼承
子類和父類有不同的拷貝賦值函數(shù)
如果父類中有指針成員懦傍,就顯性寫出父類的深拷貝賦值函數(shù),如果子類中有指針成員芦劣,就顯性寫出子類的深拷貝賦值函數(shù)粗俱,如果顯性寫出了子類的深拷貝賦值,子類的拷貝賦值函數(shù)內(nèi)一定要顯性調(diào)用父類的拷貝賦值函數(shù)虚吟。
#include <iostream>
using namespace std;
class Person
{
private:
? ? int *age;
? ? string name;
public:
? ? //無參構造
? ? Person():age(new int){cout << "Per無參構造" << endl;}
? ? //有參構造
? ? Person(string name,int age):name(name),age(new int(age))
? ? {cout << "Per的有參構造" << endl;}
? ? //拷貝構造
? ? Person(Person &other):age(new int(*(other.age)))
? ? {
? ? ? ? //*(this->age) = *(other.age);
? ? ? ? this->name = other.name;
? ? }
? ? ~Person()
? ? {
? ? ? ? cout << "釋放了堆區(qū)的空間" << age << endl;
? ? ? ? delete age;
? ? ? ? cout << "Person的析構函數(shù)" << endl;
? ? }
? ? void show()
? ? {
? ? ? ? cout << "Per中age" << *age << endl;
? ? }
? ? void show_()
? ? {
? ? ? ? cout << age << endl;
? ? }
? ? //Person的深拷貝賦值
? ? Person &operator=(const Person &other)
? ? {
? ? ? ? if(this!=&other)
? ? ? ? {
? ? ? ? ? ? this->name = other.name;
? ? ? ? ? ? *(this->age) = *(other.age);
? ? ? ? }
? ? ? ? return *this;
? ? }
};
//定義Stu類繼承自Person
//類默認是私有繼承寸认,常用的繼承方式是公有的
class Stu:public Person
{
public:
? ? int score;
public:
? ? Stu(){}
? ? //子類的有參構造,在初始化列表中顯性的調(diào)用父類的有參構造
? ? Stu(string name,int age,int score):Person(name,age),score(score)
? ? {cout << "Stu的有參構造" << endl;}
//? ? void show()
//? ? {
//? ? ? ? //cout << name << endl;
//? ? ? ? //cout << "Person的name" << Person::name << endl;
//? ? ? ? //子類中不能訪問父類繼承下來的私有成員
//? ? ? ? //cout << "Person中的name" << name << endl;
//? ? ? ? //子類中可以訪問從父類繼承下來的受保護的成員
//? ? ? ? //cout << "Person中的age" << age << endl;
//? ? }
? ? ~Stu(){cout << "Stu的析構" << endl;}
? ? //Person(Person &other)
? ? Stu(Stu &other):Person(other)? //對于Person的拷貝構造,傳子類的對象串慰,父類的引用可以引用子類的對象
? ? {
? ? ? ? this->score = other.score;
? ? ? ? cout << "Stu的拷貝構造" << endl;
? ? }
? ? Stu &operator=(const Stu &other)
? ? {
? ? ? ? if(this!=&other)
? ? ? ? {
? ? ? ? ? ? //顯性調(diào)用Person的拷貝賦值
? ? ? ? ? ? Person::operator=(other);
? ? ? ? ? ? cout << "Stu的拷貝賦值函數(shù)" << endl;
? ? ? ? ? ? this->score = other.score;
? ? ? ? }
? ? ? ? return *this;
? ? }
};
int main()
{
? ? Stu s;? //無參構造
? ? s.show_();
? ? Stu s1("zhangsan",20,100);? //有參構造
? ? cout << "s1" << "\t" ;
? ? s1.show();
? ? //拷貝構造
? ? //Stu s2 = s1;? //調(diào)用拷貝構造偏塞,需要開辟空間
? ? s = s1;
? ? cout << "s" << "\t" ;
? ? s.show();
//? ? cout << "s1的地址" << &s1 << endl;? //a0
//? ? s1.Person::show();
//? ? Person *p = &s1;
//? ? p->show();? //通過父類指針訪問到的是父類中的show函數(shù)
//? ? cout << "s1中首成員的地址" << &s1.score << endl;
? ? return 0;
}
四、多重繼承
一個子類由多個父類繼承而來/一個派生類由多個基類派生出來
格式
class B:public A,private C
class 類名:繼承權限1 類1,繼承權限2 類2·····
{
? ? //子類拓展的內(nèi)容
};
如果多個基類(父類)中有同名成員邦鲫,會發(fā)生歧義灸叼,通過類名加上域限定符訪問指定的成員。
特殊的成員函數(shù)調(diào)用和使用的規(guī)律和普通繼承時一致
多重繼承時,構造函數(shù)的調(diào)用順序怜姿,和繼承的順序有關慎冤,和初始化列表中的調(diào)用順序無關。
#include <iostream>
using namespace std;
class Person
{
public:
? ? string name;
? ? int age;
? ? Person(){cout << "p無參構造" << endl;}
? ? Person(string name,int age):name(name),age(age)
? ? {
? ? ? ? cout << "P有參構造" << endl;
? ? }
};
class Stu
{
public:
? ? int age;
? ? int score;
? ? Stu(){cout << "Stu無參構造" << endl;}
? ? Stu(int age,int score):age(age),score(score)
? ? {cout << "Stu有參構造" << endl;}
};
//A類繼承自Person類和Stu類
class A:public Person,public Stu
{
? ? int high;
public:
? ? A(){cout << "A無參構造" << endl;}
? ? A(int h,string name,int age1,int age2,int score):Stu(age2,score),Person(name,age1),high(h)
? ? {cout << "A有參構造" << endl;}
};
int main()
{
? ? A a1;? //Person的構造函數(shù)先被調(diào)用
? ? cout << "a2****************************" << endl;
? ? A a2(100,"zhangsan",78,90,23);
? ? cout << a2.Stu::age << endl;
? ? cout << a2.Person::age << endl;
? ? return 0;
}
五沧卢、菱形繼承(鉆石繼承)
公共基類的內(nèi)容會在匯集子類中保留兩份蚁堤。
對于訪問公共基類中成員時,會存在二義性的問題
如果多次繼承大型的公共基類但狭,會導致子類的內(nèi)存過大披诗。
【1】虛繼承(virtual)
虛繼承用于解決菱形繼承存在的問題,通過菱形繼承公共基類中的額內(nèi)容只會在匯集子類中保存一份立磁,不會造成子類的內(nèi)存過大呈队。
virtual關鍵字,只對關鍵字后面所跟的類起作用唱歧,表示虛繼承virtual后面的類宪摧,兩個中間基類都需要加virtual
如果使用虛繼承,對于公共基類的構造函數(shù)颅崩,需要直接使用基類名來調(diào)用(因為不知道通過那一條中間路徑繼承的基類)
雖然几于,只保留了一份公共基類,但是仍然可以通過指定路徑來訪問基類中的成員
#include <iostream>
using namespace std;
class Person
{
public:
? ? string name;
? ? int age;
? ? Person(){cout << "p無參構造" << endl;}
? ? Person(string name,int age):name(name),age(age){}
};
//Stu虛繼承Person
class Stu:virtual public Person
{
public:
? ? int score;
? ? Stu(){cout << "Stu無參構造" << endl;}
? ? Stu(int score):score(score){}
};
//B虛繼承Person
class B:virtual public Person
{
? ? int bb;
public:
? ? B(){}
? ? B(int b):bb(b){}
};
class A:public B,public Stu
{
? ? int high;
public:
? ? A(){cout << "A無參構造" << endl;}
? ? A(int h,int s,int b,int a,string name):high(h),Stu(s),B(b),Person(name,a)
? ? {
? ? }
};
int main()
{
? ? //A a1;? //Person的構造函數(shù)先被調(diào)用
? ? A a1(100,78,9,18,"zhangsan");
? ? cout << "a2****************************" << endl;
//? ? cout << a1.B::age << endl;? //指定訪問從B路徑繼承下來的age
//? ? cout << a1.Stu::age << endl;? //指定訪問從Stu路徑繼承下來的age
? ? cout << a1.age << endl;? //直接通過匯集子類來訪問基類中的成員
? ? return 0;
}