中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

時(shí)尚字體設(shè)計(jì)網(wǎng)站網(wǎng)絡(luò)營(yíng)銷推廣的方式

時(shí)尚字體設(shè)計(jì)網(wǎng)站,網(wǎng)絡(luò)營(yíng)銷推廣的方式,環(huán)保網(wǎng)站建設(shè)的主題,內(nèi)蒙古響應(yīng)式網(wǎng)站建設(shè)1. 繼承的概念及定義 1.1 繼承的概念 繼承(inheritance)機(jī)制是面向?qū)ο蟪绦蛟O(shè)計(jì)使代碼可以復(fù)用的最重要手段,他允許我們?cè)诒WC原有類的特性基礎(chǔ)上還進(jìn)行擴(kuò)展,通過(guò)繼承產(chǎn)生的類叫做派生類(子類),被繼承的類叫做基類&a…

1. 繼承的概念及定義

1.1 繼承的概念

繼承(inheritance)機(jī)制是面向?qū)ο蟪绦蛟O(shè)計(jì)使代碼可以復(fù)用的最重要手段,他允許我們?cè)诒WC原有類的特性基礎(chǔ)上還進(jìn)行擴(kuò)展,通過(guò)繼承產(chǎn)生的類叫做派生類(子類),被繼承的類叫做基類(父類)。繼承呈現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計(jì)的層次結(jié)構(gòu)。和我們之前Date類那里重載運(yùn)算符的那塊有異曲同工之妙,重載運(yùn)算符那里的實(shí)現(xiàn)是函數(shù)的復(fù)用,而繼承則是類設(shè)計(jì)層次的復(fù)用。

ok, 當(dāng)我們想創(chuàng)建兩個(gè)類一個(gè)是學(xué)生,一個(gè)是教師,他們都有一些共同的特點(diǎn)例如名字、地址、電話號(hào)碼、年齡等等的時(shí)候,但他們也有不同的一些特點(diǎn),例如學(xué)生有學(xué)號(hào),老師有職稱等等,我們就可以用繼承來(lái)實(shí)現(xiàn),創(chuàng)建一個(gè)父類Person儲(chǔ)存他們的共同特點(diǎn),然后再對(duì)父類進(jìn)行繼承出新的子類即可;

語(yǔ)法為:

class Person{};

class Teacher: public: Person{};

class Student: public: Person{};

當(dāng)我們想實(shí)現(xiàn)一個(gè)Student類和Teacher類的時(shí)候會(huì)有一些相同的信息;如下代碼所示:

#include<iostream>
using namespace std;class Student
{
public:// 進(jìn)?校園/圖書館/實(shí)驗(yàn)室刷?維碼等?份認(rèn)證void identity(){// ...}// 學(xué)習(xí)void study(){// ...}
protected:string _name = "peter"; // 姓名string _address; // 地址string _tel; // 電話int _age = 18; // 年齡int _stuid; // 學(xué)號(hào)
};
class Teacher
{
public:// 進(jìn)?校園/圖書館/實(shí)驗(yàn)室刷?維碼等?份認(rèn)證void identity(){// ...}// 授課void teaching(){//...}
protected:string _name = "張三"; // 姓名int _age = 18; // 年齡string _address; // 地址string _tel; // 電話string _title; // 職稱
};
int main()
{return 0;
}

那么我們就可以用繼承進(jìn)行解決代碼如下:

#include<iostream>
using namespace std;class Person
{
public:// 進(jìn)?校園/圖書館/實(shí)驗(yàn)室刷?維碼等?份認(rèn)證void identity(){cout << "void identity()" << _name << endl;}
protected:string _name = "張三"; // 姓名string _address; // 地址string _tel; // 電話int _age = 18; // 年齡
};class Student : public Person
{
public:// 學(xué)習(xí)void study(){// ...}
protected:int _stuid; // 學(xué)號(hào)
};class Teacher : public Person
{
public:// 授課void teaching(){//...}
protected:string title; // 職稱
};
int main()
{Student s;Teacher t;s.identity();t.identity();return 0;
}

這樣Student 和Teacher都有Person類的成員例如name、address、tel,而有不需要我們?cè)龠^(guò)多寫;

首先又在這里提一嘴就是成員變量被protected修飾的話就代表他的子類或者內(nèi)部類可以使用,而在類外或者派生類(子類)外都不可以使用,private則是子類和類外都不能使用;


1.2 繼承的定義

定義的格式:

如下圖可見(jiàn):

1. 如果基類(父類)的成員是private的話,在派生類(子類)不可以被訪問(wèn),但是這些成員也一樣會(huì)被繼承到派生類去,只是不能訪問(wèn)而已。

2. 基類(父類)的成員是protected的話,在派生類(子類)中可以被訪問(wèn)。而protected關(guān)鍵詞其實(shí)就是因?yàn)槔^承才出現(xiàn)的。

3. 繼承方式,一般是按最小級(jí)別的來(lái),級(jí)別如:public > protected > private?,如果說(shuō)繼承方式是public的話,基類成員是private修飾的,那么基類的成員訪問(wèn)限定符按最小級(jí)別來(lái)即private;如果說(shuō)繼承方式是private的話,無(wú)論基類成員是public還是protected,基類的訪問(wèn)限定符都為private。

4. 使用關(guān)鍵字class時(shí)默認(rèn)的繼承方式是private,而struct時(shí)默認(rèn)方式是public;但最好顯示寫出來(lái)。

5. 一般都是用public,便于維護(hù);


1.3 繼承類模板

顧名思義繼承一個(gè)類模板;如下代碼和注釋來(lái)看:

#include<iostream>
#include<vector>
#include<list>
#include<deque>
#define Container std::vector
using namespace std;namespace lwt
{//template<class T>//class vector//{};// stack和vector的關(guān)系,既符合is-a,也符合has-a//is-a是說(shuō)stack底層實(shí)現(xiàn)就是vector//has-a是說(shuō)包含關(guān)系,即vector可以被stack繼承,因?yàn)閟tack的特性包含vector的特性template<class T>class stack : public std::vector<T>{public://👇如果說(shuō)我們直接調(diào)用的push_back(x);的話會(huì)出錯(cuò),因?yàn)榘葱鑼?shí)例化的時(shí)候//push_back在本類里面找不到然后就會(huì)進(jìn)到父類里面找,但都沒(méi)找到,所以我們要指定一下//類域即vector<T>::void push(const T& x){// 基類是類模板時(shí),需要指定?下類域,// 否則編譯報(bào)錯(cuò):error C3861: “push_back”: 找不到標(biāo)識(shí)符// 因?yàn)閟tack<int>實(shí)例化時(shí),也實(shí)例化vector<int>了// 但是模版是按需實(shí)例化,push_back等成員函數(shù)未實(shí)例化,所以找不到//push_back(x);vector<T>::push_back(x);}void pop(){vector<T>::pop_back();}const T& top(){return vector<T>::back();}bool empty(){return vector<T>::empty();}};//下面是上面的一個(gè)新用法//我們可以使用宏在頭部定義一個(gè)Container放置std::vectortemplate<class T>class stack : public Container<T>{public:void push(const T& x){vector<T>::push_back(x);}void pop(){vector<T>::pop_back();}const T& top(){return vector<T>::back();}bool empty(){return vector<T>::empty();}};

這里再來(lái)講一下里面為什么要用vector<T>::push_back,因?yàn)槟0迨亲袷匕葱鑼?shí)例化的規(guī)則來(lái)的,class stack : public std::vector<T>,如果我們我們實(shí)例化stack<int>,那就只實(shí)例化了vector<int>,編譯器不知道我們還要實(shí)例化里面的功能,這里只是單純實(shí)例化了一個(gè)vector<int>對(duì)象,所以我們需要指定一下vector<T>域內(nèi)的push_back即可;


2. 基類和派生類之間的轉(zhuǎn)換

  • public繼承的派生類(子類)對(duì)象可以給基類(父類)的對(duì)象、指針和引用賦值。但不是把派生類(子類)對(duì)象的所有成員都賦值給基類(父類)對(duì)象,而是把原先屬于基類部分的成員賦值給基類對(duì)象;這個(gè)過(guò)程稱為切割或者切片;很好理解,就是把派生類內(nèi)不是從基類繼承來(lái)的成員切割掉;
  • 基類的對(duì)象不能賦值給派生類的對(duì)象;
  • 但是如果那個(gè)基類的對(duì)象的指針原先就是指向派生類的指針的話,那還是可以通過(guò)強(qiáng)制類型轉(zhuǎn)換賦值給派生類對(duì)象的,但是這里使用到一個(gè)dynamic_cast,這里只是演示一下;如下代碼所示:
    #include<iostream>using namespace std;
    class Person
    {
    protected://多態(tài)后面會(huì)說(shuō)virtual void func(){}
    public:Person(const string& name, const string& sex, int age):_name(name),_sex(sex),_age(age){cout << "Person(const string& name, const string& sex, int age)" << endl;cout << "name:> " << _name << endl;cout << "sex:> " << _sex << endl;cout << "age:> " << _age << endl;}string _name; // 姓名string _sex; // 性別int _age; // 年齡
    };class Student :public Person
    {
    public:Student(const string& name="lwt", const string& sex="man", int age=20):Person(name, sex, age){}int _No; //學(xué)號(hào)
    };int main()
    {Student sobj;//子類對(duì)象可以賦值給父類對(duì)象/指針/引用//這樣就是上面所說(shuō)的切割,即會(huì)把非父類對(duì)象的部分切割然后//把是父類對(duì)象的部分賦值給父類Person pobj = sobj;Person* pp = &sobj;Person& rp = sobj;//基類的指針或者引?可以通過(guò)強(qiáng)制類型轉(zhuǎn)換賦值給派?類的指針或者引?。但是必須是基類的指針//是指向派?類對(duì)象時(shí)才是安全的。這?基類如果是多態(tài)類型,可以使?RTTI(Run - Time Type//Information)的dynamic_cast 來(lái)進(jìn)?識(shí)別后進(jìn)?安全轉(zhuǎn)換。(ps:這個(gè)我們后?類型轉(zhuǎn)換章節(jié)再//單獨(dú)專?講解,這?先提?下)Student* sp1 = dynamic_cast<Student*>(pp);cout << sp1<< endl;cout << pp << endl;pp = &pobj;Student* sobj2 = dynamic_cast<Student*>(pp);//2.父類對(duì)象不能賦值給子類對(duì)象,這里會(huì)編譯報(bào)錯(cuò)//sobj = (Student)pobj;return 0;
    }

    👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇

    運(yùn)行結(jié)果為:

?這里需要提一點(diǎn)的就是,在派生類想要初始化基類的話需要調(diào)用基類的構(gòu)造函數(shù),不可以直接使用基類的成員變量在派生類的初始化鏈表初始化;


3. 繼承的作用域

3.1 隱藏

1. 在繼承體系中,基類和派生類都有獨(dú)立的作用域;

2. 派生類和基類中如果有同名的成員的話,那么就會(huì)屏蔽掉基類的成員訪問(wèn),這種就稱作隱藏;那如果我們?cè)谂缮愊胍L問(wèn)基類中被隱藏的成員我們就可以通過(guò)指定訪問(wèn)域進(jìn)行訪問(wèn)例如:基類::基類成員即可;

3. 如果是成員函數(shù)的話,構(gòu)成隱藏的條件只需要一個(gè)即函數(shù)名相同,即使他們的參數(shù)不相同也不會(huì)構(gòu)成重載,照樣構(gòu)成隱藏;如下代碼所示:

#include<iostream>
using namespace std;class Person
{
public:void Fun(){cout << "PersonFunc()" << endl;}void test(int a){cout << "Persontest()" << endl;}
protected:string _name = "小李子"; // 姓名int _num = 111; // 身份證號(hào)
};//隱藏即如果基類和派生類有同名的成員的話
//基類的成員就會(huì)被隱藏,只是用派生類的成員
//如果我們想使用基類里面的話我們就需要指定類域
//即可;//如果說(shuō)有函數(shù)名相同的則會(huì)直接隱藏基類的函數(shù),不管他們參數(shù)是否一樣
//不會(huì)構(gòu)成重載
//只會(huì)被隱藏掉class Student : public Person
{
public:void Print(){cout << _num << endl;cout << Person::_num << endl;}void Func(){cout << "StudentFunc()" << endl;}void test(){cout << "Studenttest()" << endl;}protected:int _num = 999; // 學(xué)號(hào)
};int main()
{Student s1;s1.Print();s1.Func();s1.Person::Fun();//報(bào)錯(cuò)//s1.test(1);s1.Person::test(1);return 0;
}

👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇

運(yùn)行結(jié)果為:


看完這個(gè)知識(shí)點(diǎn)我們直接就來(lái)兩道面試題;如下圖

#include<iostream>
using namespace std;
class A
{
public:void fun(){cout << "func()" << endl;}
};
class B : public A
{
public:void fun(int i){cout << "func(int i)" << i << endl;}
};
int main()
{B b;b.fun(10);b.fun();return 0;
};

答案:A,A;

解析:首先上面說(shuō)了,只要函數(shù)名相同就構(gòu)成隱藏,不管他參數(shù)相同還是不同,都不會(huì)構(gòu)成重載;所以第一題選A。

第二題:由于是構(gòu)成隱藏關(guān)系,那我們想訪問(wèn)那個(gè)無(wú)參的func的話就必須顯式調(diào)用即b.A::func();指定一定訪問(wèn)域,不然就報(bào)錯(cuò);


4. 派生類的默認(rèn)成員函數(shù)

默認(rèn)的意思就是指我們不寫,編譯器會(huì)幫我們自動(dòng)生成一個(gè);

1. 基類如果沒(méi)有默認(rèn)構(gòu)造的話,那么在派生類的構(gòu)造函數(shù)里需要調(diào)用基類的構(gòu)造函數(shù)對(duì)基類的成員進(jìn)行初始化,調(diào)用基類的構(gòu)造函數(shù)就類似于匿名對(duì)象一樣,但這里不叫匿名對(duì)象;如下代碼所示:

#include<iostream>
using namespace std;class Person
{
public:Person(const string& name	):_name(name){cout << "Person()" << endl;}protected:string _name;
};class Student:public Person
{
public:Student(const string& name, int num):Person(name),_num(num){cout << "Student()" << endl;}protected:int _num;
};int main()
{Student s1("lwt", 12);return 0;
}

👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇

運(yùn)行結(jié)果為:


2. 拷貝構(gòu)造的也是一樣,派生類的拷貝構(gòu)造函數(shù)必須調(diào)用基類的拷貝構(gòu)造完成基類的初始化;

#include<iostream>
using namespace std;class Person
{
public:Person(const string& name	):_name(name){cout << "Person()" << endl;}Person(const Person& p):_name(p._name){cout << "Person拷貝構(gòu)造調(diào)用" << endl;}protected:string _name;
};class Student:public Person
{
public:Student(const string& name, int num):Person(name),_num(num){cout << "Student()" << endl;}// 嚴(yán)格說(shuō)Student拷貝構(gòu)造默認(rèn)生成的就夠用了// 如果有需要深拷貝的資源,才需要自己實(shí)現(xiàn)Student(const Student& s1):Person(s1),_num(s1._num){cout << "Student拷貝構(gòu)造調(diào)用" << endl;}protected:int _num;
};int main()
{Student s1("lwt", 12);Student s2(s1);return 0;
}

👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇

運(yùn)行結(jié)果為:


3. 派生類的operator=必須調(diào)用基類的operator=完成基類的賦值。但需要注意的是派生類的operator=隱藏了基類的operator=,所以要顯示調(diào)用基類的operator=。

#include<iostream>
using namespace std;class Person
{
public:Person(const string& name	):_name(name){cout << "Person()" << endl;}Person(const Person& p):_name(p._name){cout << "Person拷貝構(gòu)造調(diào)用" << endl;}Person& operator=(const Person& p){cout << "Person& operator=(const Person& p)" << endl;if (this != &p){_name = p._name;}return *this;}
protected:string _name;
};class Student:public Person
{
public:Student(const string& name, int num):Person(name),_num(num){cout << "Student()" << endl;}// 嚴(yán)格說(shuō)Student拷貝構(gòu)造默認(rèn)生成的就夠用了// 如果有需要深拷貝的資源,才需要自己實(shí)現(xiàn)Student(const Student& s1):Person(s1),_num(s1._num){cout << "Student拷貝構(gòu)造調(diào)用" << endl;}void print(){cout << _num << endl;cout << _name << endl;}Student& operator=(const Student& s1){if (this != &s1){//父類和子類的operator=構(gòu)成隱藏關(guān)系Person::operator=(s1);_num = s1._num;}return *this;}protected:int _num;
};int main()
{Student s1("lwt", 12);Student s2(s1);Student s3("lll", 15);cout << endl;s2.print();cout << endl;s2 = s3;s2.print();return 0;
}

👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇

運(yùn)行結(jié)果為:

有一個(gè)很巧妙的點(diǎn)就在于,你看在Student內(nèi)重載operator=那里的Person::operator=(s1),如果我們沒(méi)有學(xué)到基類和派生類之間的轉(zhuǎn)換的話我們不懂為什么Person內(nèi)重載的operator的參數(shù)是Person,而在這里我們傳了類型為Student的s1進(jìn)去,這里就造成了切割或切片。


4. 派生類對(duì)象初始化先調(diào)用基類構(gòu)造再調(diào)用派生類構(gòu)造;

#include<iostream>
using namespace std;class Person
{
public:Person(const string& name	):_name(name){cout << "Person()" << endl;}Person(const Person& p):_name(p._name){cout << "Person拷貝構(gòu)造調(diào)用" << endl;}protected:string _name;
};class Student:public Person
{
public:Student(const string& name, int num):Person(name),_num(num){cout << "Student()" << endl;}// 嚴(yán)格說(shuō)Student拷貝構(gòu)造默認(rèn)生成的就夠用了// 如果有需要深拷貝的資源,才需要自己實(shí)現(xiàn)Student(const Student& s1):Person(s1),_num(s1._num){cout << "Student拷貝構(gòu)造調(diào)用" << endl;}void print(){cout << _num << endl;cout << _name << endl;}protected:int _num;
};int main()
{Student s1("lwt", 12);return 0;
}

👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇

運(yùn)行結(jié)果為:


5. 析構(gòu)函數(shù)的調(diào)用,如果說(shuō)這里面沒(méi)有動(dòng)態(tài)申請(qǐng)空間的話,默認(rèn)的析構(gòu)函數(shù)也夠用了,如果動(dòng)態(tài)申請(qǐng)了的話我們就需要寫析構(gòu)函數(shù)清理申請(qǐng)的內(nèi)存,那問(wèn)題又來(lái)了,我們不僅要清理派生類里面的空間,還要清理基類內(nèi)的空間,那么我們就需要寫兩個(gè)析構(gòu)函數(shù),但是呢問(wèn)題又來(lái)了,基類的析構(gòu)和派生類的析構(gòu)構(gòu)成隱藏,原因是無(wú)論析構(gòu)函數(shù)的名字怎么樣,最后都會(huì)被編譯器轉(zhuǎn)為一個(gè)名為destructor()的函數(shù),所以會(huì)導(dǎo)致隱藏,那么我們就需要指定一下作用域;如下代碼所示:

#include<iostream>
using namespace std;
class Person
{
public:Person(const char* name = "胡圖圖"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}~Person(){cout << "~Person()" << endl;}
protected:string _name; // 姓名
};class Student : public Person
{
public:Student(const char* name, int num, const char* addrss):Person(name), _num(num), _addrss(addrss){}// 嚴(yán)格說(shuō)Student拷貝構(gòu)造默認(rèn)生成的就夠用了// 如果有需要深拷貝的資源,才需要自己實(shí)現(xiàn)Student(const Student& s):Person(s), _num(s._num), _addrss(s._addrss){// 深拷貝}// 嚴(yán)格說(shuō)Student析構(gòu)默認(rèn)生成的就夠用了// 如果有需要顯示釋放的資源,才需要自己實(shí)現(xiàn)// 析構(gòu)函數(shù)都會(huì)被特殊處理成destructor() ~Student(){// 子類的析構(gòu)和父類析構(gòu)函數(shù)也構(gòu)成隱藏關(guān)系// 規(guī)定:不需要顯示調(diào)用,子類析構(gòu)函數(shù)之后,會(huì)自動(dòng)調(diào)用父類析構(gòu)// 這樣保證析構(gòu)順序,先子后父,顯示調(diào)用取決于實(shí)現(xiàn)的人,不能保證// 先子后父cout<<"~Student()"<<endl;Person::~Person();delete _ptr;}
protected:int _num = 1; //學(xué)號(hào)string _addrss = "翻斗花園";int* _ptr = new int[10];
};int main()
{Student* ptr = new Student("胡圖圖",10,"翻斗花園");delete ptr;return 0;
}

👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇

運(yùn)行結(jié)果為:

這里為什么會(huì)有兩個(gè)~Person呢?原因是其實(shí)派生類的析構(gòu)函數(shù)調(diào)用后會(huì)自動(dòng)調(diào)用基類的析構(gòu)函數(shù),所以不需要我們寫;我們可以把~Student里面的Person::~Person()刪掉即可;

👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇

運(yùn)行結(jié)果為:

最后總結(jié)一下:一般如果沒(méi)有深拷貝的話拷貝構(gòu)造和賦值運(yùn)算符重載不需要我們自己寫,用默認(rèn)的就行,析構(gòu)函數(shù)也是;然后析構(gòu)函數(shù)的調(diào)用順序是先子后父


5. 實(shí)現(xiàn)一個(gè)不能被繼承的類

方法一:讓構(gòu)造函數(shù)的訪問(wèn)限定符為private,這樣就無(wú)法調(diào)用了。

#include<iostream>
using namespace std;class Person
{
public:private:Person(){}
};class Student : public Person
{
public:
};
int main()
{Student s1;return 0;
}

方法二:c++11新加的關(guān)鍵字final,final加到基類的類名后就不能被繼承了。


6. 繼承和友元

友元的關(guān)系不能被繼承,說(shuō)明基類的友元不能訪問(wèn)派生類的私有保護(hù)成員;舉個(gè)很簡(jiǎn)單的例子方便記憶,“父親的朋友不是你的朋友”;如下代碼所示:


7. 繼承與靜態(tài)成員

基類定義了static靜態(tài)成員,則整個(gè)繼承體系只有一個(gè)這樣的成員,派生出多少個(gè)派生類,都只有一個(gè)static成員實(shí)例;

#include<iostream>
using namespace std;class Person
{
public:string _name;static int _count;};int Person::_count = 0;class Student:public Person
{
protected:int _stuNum;
};int main()
{Student s;Person p;//地址不一樣說(shuō)明已經(jīng)繼承了cout << &s._name << endl;cout << &p._name << endl;//地址一樣說(shuō)明只有一份cout << &s._count << endl;cout << &p._count << endl;return 0;
}

👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇? 👇

運(yùn)行結(jié)果為:


7. 多繼承以及菱形繼承的問(wèn)題

7.1 繼承模型

單繼承:一個(gè)派生類只有一個(gè)基類。

多繼承:一個(gè)派生類有兩個(gè)或兩個(gè)以上的基類,“我爸”有一個(gè)Son的基類和Dad的基類,多繼承對(duì)象在內(nèi)存中的模型是先繼承的基類放在前面,后繼承的放后面。

菱形繼承:是多繼承的一種特殊情況,可能祖師爺那會(huì)喝醉了沒(méi)想到這個(gè)情況吧。菱形繼承會(huì)導(dǎo)致數(shù)據(jù)冗余和二義性的問(wèn)題,Assistant里面有兩份Person,因?yàn)镾tudent里面有一份Person,Teacher里面也有一份Person;

#include<iostream>
using namespace std;class Person
{
public:string _name;
};class Student :public Person
{
protected:int _num;
};class Teacher :public Person
{
protected:int _id;
};class Assistant :public Student, public Teacher
{
protected:string _majorCourse;
};int main()
{Assistant a;a._name() = "胡圖圖";
}

如果我們想解決這個(gè)問(wèn)題的話可以指定訪問(wèn)指定的基類成員就可以了;


7.2 虛繼承

有了多繼承,菱形繼承就無(wú)法避免最好不要實(shí)現(xiàn)出來(lái),但我們也可以在其中做出一些操作;在兩個(gè)會(huì)繼承到同一個(gè)基類的派生類處加關(guān)鍵字virtual即可;如下代碼所示:

#include<iostream>
using namespace std;class Person
{
public:string _name;
};class Student :public virtual Person
{
protected:int _num;
};class Teacher :public virtual Person
{
protected:int _id;
};class Assistant :public Student, public Teacher
{
public:
protected:string _majorCourse;
};int main()
{Assistant a;a._name = "胡圖圖";//a.Student::_name = "胡圖圖";//a.Teacher::_name = "胡英俊";return 0;
}

這串代碼就可以執(zhí)行了;而這個(gè)東西的原理就是把那些繼承的數(shù)據(jù),通過(guò)虛基表和虛基指針來(lái)管理這些共享的數(shù)據(jù),從而避免了數(shù)據(jù)的冗余;簡(jiǎn)單點(diǎn)理解就是放在一個(gè)公共區(qū)域共同使用。


8. 繼承和組合

繼承是子類繼承了父類的特性,可以說(shuō)子類其實(shí)就是一個(gè)特殊的父類,而組合則是將另一個(gè)類當(dāng)做自己的成員變量進(jìn)行使用;

繼承是is-a的關(guān)系,舉個(gè)例子,例如狗是一個(gè)動(dòng)物,那么狗就是子類,而動(dòng)物就是父類,而狗有動(dòng)物的所有特性,即是有個(gè)新的類需要一個(gè)類的所有特性的時(shí)候就可以使用繼承。

而組合是has-a,這里也舉個(gè)例子就是汽車有一個(gè)輪子,那么我們有一個(gè)class Car{class wheels{};};,即有個(gè)類需要某些特定的功能的時(shí)候則可以使用組合。組合可以很好地保護(hù)類的安全性不破壞封裝;


END!

http://www.risenshineclean.com/news/856.html

相關(guān)文章:

  • 樂(lè)清網(wǎng)站建設(shè)公司網(wǎng)絡(luò)軟文營(yíng)銷案例3篇
  • 免費(fèi)網(wǎng)站建設(shè)加盟亞洲衛(wèi)星電視網(wǎng)參數(shù)表
  • 網(wǎng)站建設(shè) 中企動(dòng)力公司搭建網(wǎng)站的步驟和順序
  • 網(wǎng)站app開(kāi)發(fā)平臺(tái)百度非企渠道開(kāi)戶
  • 孝感網(wǎng)站開(kāi)發(fā)的公司電話集客營(yíng)銷軟件
  • 攀枝花建設(shè)工程有限責(zé)任公司網(wǎng)站一元友情鏈接平臺(tái)
  • 池州專業(yè)網(wǎng)站建設(shè)谷歌搜索引擎鏡像
  • 網(wǎng)站設(shè)計(jì) 電子購(gòu)物網(wǎng)站設(shè)計(jì)網(wǎng)絡(luò)精準(zhǔn)推廣
  • 電商網(wǎng)站建設(shè)推廣企業(yè)網(wǎng)絡(luò)規(guī)劃設(shè)計(jì)方案
  • 網(wǎng)站建設(shè)的結(jié)論和體會(huì)百度推廣營(yíng)銷中心
  • 柳州正規(guī)網(wǎng)站制作公司發(fā)稿網(wǎng)
  • 牛街網(wǎng)站建設(shè)免費(fèi)網(wǎng)站推廣軟件哪個(gè)好
  • 電子書籍網(wǎng)站開(kāi)發(fā)推廣鏈接點(diǎn)擊器網(wǎng)頁(yè)
  • 如何開(kāi)一個(gè)微信公眾號(hào)seo顧問(wèn)合同
  • 昆明企業(yè)自助建站系統(tǒng)百度官網(wǎng)客服
  • 曹縣網(wǎng)站開(kāi)發(fā)抓取關(guān)鍵詞的軟件
  • 虛擬幣挖礦網(wǎng)站開(kāi)發(fā)新鄉(xiāng)seo網(wǎng)絡(luò)推廣費(fèi)用
  • 互聯(lián)網(wǎng)門戶網(wǎng)站世界比分榜
  • 網(wǎng)站建設(shè)目標(biāo)定位推廣排名seo
  • jsp網(wǎng)站seo優(yōu)化百度競(jìng)價(jià)推廣開(kāi)戶多少錢
  • 百度海外視頻網(wǎng)站建設(shè)幽默軟文經(jīng)典案例300
  • 釣魚網(wǎng)站開(kāi)發(fā)百度百度一下百度
  • 做安卓icon圖標(biāo)下載網(wǎng)站網(wǎng)站推廣優(yōu)化方法
  • 提升網(wǎng)站關(guān)鍵詞排名推廣策劃方案怎么做
  • 做中國(guó)旅游網(wǎng)站的目的與必要性廣豐網(wǎng)站seo
  • 網(wǎng)頁(yè)設(shè)計(jì)作品網(wǎng)站seo關(guān)鍵詞智能排名
  • ps網(wǎng)站設(shè)計(jì)素材手機(jī)百度搜索引擎入口
  • 物流公司哪家便宜又好河南純手工seo
  • h5 css3 網(wǎng)站開(kāi)發(fā)實(shí)例熱搜榜上2023年熱門話題
  • 花錢推廣的網(wǎng)絡(luò)平臺(tái)廣州seo和網(wǎng)絡(luò)推廣