由于C++的類沒學好。這是在另一個班學習的筆記
一、面向?qū)ο蟮娜筇卣?/p>
????封裝、繼承和多態(tài)
二、類之間的繼承
【1】訪問權(quán)限
????public:類中、子類和類外都可以訪問
????private:類中可以訪問,類外和子類中都不能訪問
????protected:類中和子類可以訪問,類外不能訪問
【2】繼承
????繼承指的是,基于已有類,創(chuàng)建出新類的過程。
????基類和派生類
????父類和子類
【3】繼承的作用
? ? ? 能提高代碼的復用性,父類/基類中原有的內(nèi)容,在子類/派生類中無需再定義,直接使用即可
繼承是實現(xiàn)多態(tài)的前提
【4】繼承的格式
????已有class A,要創(chuàng)建一個class B繼承自A
????class B:權(quán)限 A? ----->創(chuàng)建一個B類,用特定的權(quán)限繼承方式繼承自A
????A類可以被稱為父類、基類
????B類可以被稱為子類、派生類
????class B:public A{}? ---->B類公有繼承A類
????class B:private A{}? ---->B類私有繼承A類
????class B:protected A{}? ---->B類受保護的繼承A類
三種繼承權(quán)限? ? ? ? ? ? ? ? ? ?
????父類中訪問權(quán)限? ??
? ? ? ?public|protected|private? ? ? public|protected|private? ? ? public|protected|private?
????繼承方式? ? ? ? ? ? ? ?
?????????????????????????public? ? ? ? ? ? ? ? ? ? ? ????????? private? ? ? ? ? ? ? ? ? ? ? ? ? protected? ? ? ? ? ?
子類中訪問權(quán)限? ??
????????public|protected|不能訪問? ? ? private|private|不能訪問? ? ? ? protected|protected|不能訪問
【5】子類對父類中成員的繼承
子類會繼承父類中的所有成員,包括私有成員
類之間的繼承關(guān)系,可以理解為是包含關(guān)系
子類中從父類繼承的成員,先存放,放在首地址,父類的指針/引用可以指向子類的對象
父類的指針,可以訪問的空間,只有父類本身的內(nèi)容,子類的指針可以訪問的空間包含父類繼承的和子類拓展的

【6】子類中存在和父類同名成員時
????通過子類對象默認訪問的是,子類的成員
????如果想要訪問父類的成員,使用類名加上域標識符可以訪問父類中的內(nèi)容
????或者也可以通過父類的指針指向子類對象,再來訪問
三、繼承中特殊的成員函數(shù)
這四個成員函數(shù)都不會被繼承
【1】構(gòu)造函數(shù)
父類中的構(gòu)造函數(shù)不會被繼承
實例化子類對象時,先調(diào)用父類中的構(gòu)造函數(shù),再調(diào)用子類中的構(gòu)造函數(shù)
如果父類中只有有參構(gòu)造,子類必須在構(gòu)造函數(shù)的初始化列表中顯性的調(diào)用父類的有參構(gòu)造
【2】析構(gòu)函數(shù)
父類中的析構(gòu)函數(shù)不會被子類繼承
先析構(gòu)子類,再析構(gòu)父類
有指針成員的情況:如果父類中有指針成員,需要在父類的析構(gòu)函數(shù)中手動釋放堆區(qū)的空間;如果子類中有指針成員,需要在子類的析構(gòu)函數(shù)中手動釋放堆區(qū)的空間
父類的析構(gòu)函數(shù),不需要再子類中手動調(diào)用,系統(tǒng)會自動調(diào)用析構(gòu)函數(shù)
【3】拷貝構(gòu)造函數(shù)
申請空間并初始化
如果父類中有指針成員,繼承時會不會涉及到深淺拷貝問題?會
父類的拷貝構(gòu)造不會被繼承
如果父類中有指針成員,需要顯性寫出父類的深拷貝函數(shù);如果指針成員在子類中九顯性寫出子類的深拷貝函數(shù)
子類的拷貝構(gòu)造需要顯性調(diào)用父類的拷貝構(gòu)造,直接傳子類的對象
【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:
? ? //無參構(gòu)造
? ? Person():age(new int){cout << "Per無參構(gòu)造" << endl;}
? ? //有參構(gòu)造
? ? Person(string name,int age):name(name),age(new int(age))
? ? {cout << "Per的有參構(gòu)造" << endl;}
? ? //拷貝構(gòu)造
? ? 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的析構(gòu)函數(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(){}
? ? //子類的有參構(gòu)造,在初始化列表中顯性的調(diào)用父類的有參構(gòu)造
? ? Stu(string name,int age,int score):Person(name,age),score(score)
? ? {cout << "Stu的有參構(gòu)造" << 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的析構(gòu)" << endl;}
? ? //Person(Person &other)
? ? Stu(Stu &other):Person(other)? //對于Person的拷貝構(gòu)造,傳子類的對象,父類的引用可以引用子類的對象
? ? {
? ? ? ? this->score = other.score;
? ? ? ? cout << "Stu的拷貝構(gòu)造" << 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;? //無參構(gòu)造
? ? s.show_();
? ? Stu s1("zhangsan",20,100);? //有參構(gòu)造
? ? cout << "s1" << "\t" ;
? ? s1.show();
? ? //拷貝構(gòu)造
? ? //Stu s2 = s1;? //調(diào)用拷貝構(gòu)造,需要開辟空間
? ? 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 類名:繼承權(quán)限1 類1,繼承權(quán)限2 類2·····
{
? ? //子類拓展的內(nèi)容
};
如果多個基類(父類)中有同名成員,會發(fā)生歧義,通過類名加上域限定符訪問指定的成員。
特殊的成員函數(shù)調(diào)用和使用的規(guī)律和普通繼承時一致
多重繼承時,構(gòu)造函數(shù)的調(diào)用順序,和繼承的順序有關(guān),和初始化列表中的調(diào)用順序無關(guān)。
#include <iostream>
using namespace std;
class Person
{
public:
? ? string name;
? ? int age;
? ? Person(){cout << "p無參構(gòu)造" << endl;}
? ? Person(string name,int age):name(name),age(age)
? ? {
? ? ? ? cout << "P有參構(gòu)造" << endl;
? ? }
};
class Stu
{
public:
? ? int age;
? ? int score;
? ? Stu(){cout << "Stu無參構(gòu)造" << endl;}
? ? Stu(int age,int score):age(age),score(score)
? ? {cout << "Stu有參構(gòu)造" << endl;}
};
//A類繼承自Person類和Stu類
class A:public Person,public Stu
{
? ? int high;
public:
? ? A(){cout << "A無參構(gòu)造" << endl;}
? ? A(int h,string name,int age1,int age2,int score):Stu(age2,score),Person(name,age1),high(h)
? ? {cout << "A有參構(gòu)造" << endl;}
};
int main()
{
? ? A a1;? //Person的構(gòu)造函數(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關(guān)鍵字,只對關(guān)鍵字后面所跟的類起作用,表示虛繼承virtual后面的類,兩個中間基類都需要加virtual
如果使用虛繼承,對于公共基類的構(gòu)造函數(shù),需要直接使用基類名來調(diào)用(因為不知道通過那一條中間路徑繼承的基類)
雖然,只保留了一份公共基類,但是仍然可以通過指定路徑來訪問基類中的成員

#include <iostream>
using namespace std;
class Person
{
public:
? ? string name;
? ? int age;
? ? Person(){cout << "p無參構(gòu)造" << endl;}
? ? Person(string name,int age):name(name),age(age){}
};
//Stu虛繼承Person
class Stu:virtual public Person
{
public:
? ? int score;
? ? Stu(){cout << "Stu無參構(gòu)造" << 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無參構(gòu)造" << 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的構(gòu)造函數(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;
}