C++课堂笔记0716
int *ptr;
ptr++;
(*ptr)++
*ptr++;
int a = 5;
int &b =a;
b++;
1.繼承
基類中,在類內(nèi),public,protected, private都是可以隨意訪問的;在基類的對象中,只能訪問public成員;
public繼承: 基類的public成員,在派生類中依舊是public屬性,派生類的對象可訪問以訪問;
? ? ? ? ? ? ?基類中的private成員,在派生類中是private屬性,派生類中的對象不可以訪問;派生類中也不可以訪問;
? ? ? ? ? ? ?基類中的protected成員,在派生類中是protected屬性,派生類的對象中不可以訪問,派生類中是可以訪問基類的protected成員的;
private繼承:基類中的public成員,在派生類中是private屬性;在派生類對象中是不可以訪問;基類中public變成派生類中private, 在派生類中是可以訪問的;
? ? ? ? ? ? ?基類中private成員,在派生類中是private屬性,在派生類和派生對象中都是不可以訪問的;
? ? ? ? ? ? ?基類中protected成員,在派生類中是private屬性,在派生類中是可以訪問的,在派生類的對象中是不可以訪問的;
protected繼承: ?基類中public成員,在派生類中是protected屬性,在派生類中是可以直接訪問,在派生類對象中無法訪問;
? ? ? ? ? ? ? ? 。。。protected 成員,在派生類中protected屬性,在派生類中可直接訪問,在派生類對象中不能訪問;
? ? ? ? ? ? ? ? 基類中private成員,在派生類中private屬性,在派生類中無法訪問,派生類對象無法訪問;
? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ??
?using 改變權(quán)限:把public可以改成保護(hù)的,私有的;
? ? ? ? ? ? ? ? ?protected可以改成public,私有的;
? ? ? ? ? ? ? ? ?private 不能改;
2。名字遮蔽
在繼承中不存在重載,發(fā)生遮蔽;派生類函數(shù)名和基類函數(shù)名相同,不論參數(shù)如何,名字相同就發(fā)生遮蔽;
3. 繼承的時候內(nèi)存模型
派生類中的內(nèi)存是:基類中變量所占空間+ 派生類自己的變量空間;
成員函數(shù)仍然在代碼區(qū), 共享;
4。派生類構(gòu)造函數(shù)
派生類構(gòu)造函數(shù)調(diào)用基類的構(gòu)造函數(shù)來實現(xiàn),不能放在函數(shù)體中調(diào)用,因為基類的構(gòu)造函數(shù)不能被繼承;
派生類構(gòu)造函數(shù)調(diào)用的基類的構(gòu)造函數(shù),參數(shù)是實參,不是形參;
5。派生類的析構(gòu)函數(shù)
構(gòu)造函數(shù),析構(gòu)函數(shù)都是不能被繼承的;
A-〉B-〉C的派生順序,構(gòu)造函數(shù)順序:A-〉B-〉C ,析構(gòu)順序C-〉B-〉A(chǔ);
6。多繼承
類A,B,C,
class D:public A,public B,public C{};
基類構(gòu)造函數(shù)出現(xiàn)的順序和繼承時的順序有關(guān);
7。命名沖突,虛繼承
class B:virtual public A{ ?};
虛繼承是表示派生類愿意共享他的基類;
被共享的基類,叫做虛基類;
8。多繼承的構(gòu)造函數(shù)(虛繼承)
構(gòu)造函數(shù)是受間接基類影響,不是直接基類;
A----B,C -- D
?B,C是D的直接基類;
?A是D的間接基類;
細(xì)節(jié):
一.引用
引用是變量的一個別名,通過這個別名和原來的名字都可以找到這份數(shù)據(jù)。
一個人的名字和綽號,表示同一個人。
1。引用和變量
<類型> ?&name = ?data;
引用必須在定義的時候同時初始化,后面不能再引用其他數(shù)據(jù),類似于const
;
#include <iostream>
using namespace std;
int main()
{
? ? int a = 99;
? ? int &b = a;
? ??
? ? cout<<a<<","<<b<<endl;
? ? cout<<&a<<","<<&b<<endl;
? ? return 0;
}
引用在定義的時候加&,使用的時候不用,加&表示地址。
不希望引用修改數(shù)據(jù),就在前面加const
;
const <類型> ?&name = ?data;或
<類型> const ?&name = ?data;
2。引用作為函數(shù)參數(shù)
用引用作為形參,調(diào)用時形參和實參就綁定在一起,指向同一份數(shù)據(jù),如同C中的地址傳遞。
修改形參,實參也改變,不會出現(xiàn)C中數(shù)值傳遞的時候?qū)崊⒉桓淖儭?br />
#include <iostream>
using namespace std;
void swap1(int a, int b);
void swap2(int *p1, int *p2);
void swap3(int &a, int &b);
int main(){
? ? int num1, num2;
? ? cout<<"Input two integers: ";
? ? cin>>num1>>num2;
? ? swap1(num1, num2);
? ? cout<<num1<<" "<<num2<<endl;
? ?
? ? cout<<"Input two integers: ";
? ? cin>>num1>>num2;
? ? swap2(&num1, &num2);
? ? cout<<num1<<" "<<num2<<endl;
? ?
? ? cout<<"Input two integers: ";
? ? cin>>num1>>num2;
? ? swap3(num1, num2);
? ? cout<<num1<<" "<<num2<<endl;
? ? return 0;
}
//直接傳遞參數(shù)內(nèi)容
void swap1(int a, int b){
? ? int temp = a;
? ? a = b;
? ? b = temp;
}
//傳遞指針
void swap2(int *p1, int *p2){
? ? int temp = *p1;
? ? *p1 = *p2;
? ? *p2 = temp;
}
//按引用傳參 ?a,b分別綁定num1,num2了
void swap3(int &a, int &b){
? ? int temp = a;
? ? a = b;
? ? b = temp;
}?
3。引用作為函數(shù)返回值
#include <iostream>
using namespace std;
int &sum(int &num)
{
? ? num = num +1;
? ? return num;
}
int main()
{
? ? int n = 20;
? ? int m = sum(n);
? ? cout<<m<<endl;
? ? return ?0;
}
注意:不能返回局部變量的引用;
如:
#include <iostream>
using namespace std;
int &plus10(int &n){
? ? int m = n + 10;
? ? return m; ?//返回局部數(shù)據(jù)的引用
}
int main(){
? ? int num1 = 10;
? ? int num2 = plus10(num1);
? ? cout<<num2<<endl;
? ? int &num3 = plus10(num1);
? ? int &num4 = plus10(num3);
? ? cout<<num3<<" "<<num4<<endl;
? ? return 0;
}
4。引用的本質(zhì),和指針的區(qū)別
引用只是對指針進(jìn)行了封裝,底層還是通過指針實現(xiàn)的。
4.1 引用必須在定義時初始化,從一而終,不能指向其他數(shù)據(jù);
指針沒這個限制,不一定賦值,也能指向任意數(shù)據(jù)。
4.2 可以有const指針,但是沒有const引用;?
int a = 20;
int & const r = a; error
const int *const ptr ;
多此一舉
3. 指針可以有多級:int **p;但引用int &&p是錯誤的;
可以如下:
int a = 10;
int &r = a;
int &rr = r;
4. 指針和引用的自增++,自減--表示不一樣。
? 指針表示指向的地址發(fā)生改變,指向下一個單元;
? 引用表示指向的值改變;
? char a='c' ; --- &a = 0x10000000;
? char *ptr=&a;
? ptr++;
? ptr--;
? 0x100000000;
??
? int a = 3;
? int &b= a;
? b++;
? b--;
??
??
??
? #include <iostream>
using namespace std;
int main (){
? ? int a = 10;
? ? int &r = a;
? ? r++;
? ? cout<<r<<endl;
? ?
? ? int arr[2] = { 27, 84 };
? ? int *p = arr;
? ? p++;
? ? cout<<*p<<endl;
? ? return 0;
}
二.繼承和派生?
一個人的特征,在血型,膚色,身材,相貌方面有父母的特征,同時和兄弟姐妹有區(qū)別的特征。
2.1 概念
繼承(Inheritance)可以理解為一個類從另一個類獲取成員變量和成員函數(shù)的過程。
例如類 B 繼承于類 A,那么 B 就擁有 A 的成員變量和成員函數(shù)。
被繼承的類稱為父類或基類,繼承的類稱為子類或派生類。
定義新類的時候可以從一個或多個既有類中繼承所有的數(shù)據(jù)成員和函數(shù)成員,然后再加上自己的
新成員或重新定義由繼承得到的成員。
繼承格式:
class 派生類名:[繼承方式] 基類名{
? ? 派生類新增加的成員
};
#include<iostream>
using namespace std;
//基類 Pelple
class People{
public:
? ? void setname(char *name);
? ? void setage(int age);
? ? char *getname();
? ? int getage();
private:
? ? char *m_name;
? ? int m_age;
};
void People::setname(char *name){ m_name = name; }
void People::setage(int age){ m_age = age; }
char* People::getname(){ return m_name; }
int People::getage(){ return m_age;}
//派生類 Student
class Student: public People{
public:
? ? void setscore(float score);
? ? float getscore();
private:
? ? float m_score;
};
void Student::setscore(float score){ m_score = score; }
float Student::getscore(){ return m_score; }
int main(){
? ? Student stu;
? ? stu.setname("小明");
? ? stu.setage(16);
? ? stu.setscore(95.5f);
? ? cout<<stu.getname()<<"的年齡是 "<<stu.getage()<<",成績是 "<<stu.getscore()<<endl;
? ? return 0;
}
class Student: public People
這就是聲明派生類的語法。class 后面的“Student”是新聲明的派生類,冒號后面的“People”是已經(jīng)存在的基類。
在“People”之前有一關(guān)鍵宇 public,用來表示是公有繼承。
2.2 ?繼承的權(quán)限?
C++繼承的一般語法為:
class 派生類名:[繼承方式] 基類名{
? ? 派生類新增加的成員
};
繼承方式限定了基類成員在派生類中的訪問權(quán)限,包括 public(公有的)、private(私有的)和 protected(受保護(hù)的)。
此項是可選項,如果不寫,默認(rèn)為 private(成員變量和成員函數(shù)默認(rèn)也是 private)。
類成員的訪問權(quán)限由高到低依次為 public --> protected --> private,
?public 和 private:public 成員可以通過對象來訪問,private 成員不能通過對象訪問
?
?protected 成員和 private 成員類似,也不能通過對象訪問。
?但是當(dāng)存在繼承關(guān)系時,protected 和 private 就不一樣了:
?基類中的 protected 成員可以在派生類中使用,而基類中的 private 成員不能在派生類中使用。
public、protected、private 指定繼承方式
不同的繼承方式會影響基類成員在派生類中的訪問權(quán)限。
1) public繼承方式
基類中所有 public 成員在派生類中為 public 屬性;
基類中所有 protected 成員在派生類中為 protected 屬性;
基類中所有 private 成員在派生類中不能使用。
2) protected繼承方式
基類中的所有 public 成員在派生類中為 protected 屬性;
基類中的所有 protected 成員在派生類中為 protected 屬性;
基類中的所有 private 成員在派生類中不能使用。
3) private繼承方式
基類中的所有 public 成員在派生類中均為 private 屬性;
基類中的所有 protected 成員在派生類中均為 private 屬性;
基類中的所有 private 成員在派生類中不能使用。
基類中:
public成員:在基類,派生類的類內(nèi),和對象都可以訪問;
private成員:只能是當(dāng)前類的類內(nèi)訪問,對象和派生類的類內(nèi)和對象都不可以訪問;
public成員: 基類和派生類的對象都不可以訪問,但是基類和派生類類內(nèi)可以訪問;
1。 繼承方式中的 public、protected、private 是用來指明基類成員在派生類中的最高訪問權(quán)限的。
2) 不管繼承方式如何,基類中的 private 成員在派生類中始終不能使用(不能在派生類的成員函數(shù)中訪問或調(diào)用)
3) 如果希望基類的成員能夠被派生類繼承并且毫無障礙地使用,那么這些成員只能聲明為 public 或 protected;
只有那些不希望在派生類中使用的成員才聲明為 private。
4) 如果希望基類的成員既不向外暴露(不能通過對象訪問),還能在派生類中使用,那么只能聲明為 protected。
基類的 private 成員是能夠被繼承的,并且(成員變量)會占用派生類對象的內(nèi)存,它只是在派生類中不可見,
導(dǎo)致無法使用罷了。private 成員的這種特性,能夠很好的對派生類隱藏基類的實現(xiàn),以體現(xiàn)面向?qū)ο蟮姆庋b性。
#include<iostream>
using namespace std;
//基類People
class People{
public:
? ? void setname(char *name);
? ? void setage(int age);
? ? void sethobby(char *hobby);
? ? char *gethobby();
protected:
? ? char *m_name;
? ? int m_age;
private:
? ? char *m_hobby;
};
void People::setname(char *name){ m_name = name; }
void People::setage(int age){ m_age = age; }
void People::sethobby(char *hobby){ m_hobby = hobby; }
char *People::gethobby(){ return m_hobby; }
//派生類Student
class Student: public People{
public:
? ? void setscore(float score);
protected:
? ? float m_score;
};
void Student::setscore(float score){ m_score = score; }
//派生類Pupil
class Pupil: public Student{
public:
? ? void setranking(int ranking);
? ? void display();
private:
? ? int m_ranking;
};
void Pupil::setranking(int ranking){ m_ranking = ranking; }
void Pupil::display(){
? ? cout<<m_name<<"的年齡是"<<m_age<<",考試成績?yōu)?#34;<<m_score<<"分,班級排名第"<<m_ranking<<",TA喜歡"<<gethobby()<<"。"<<endl;
}
int main(){
? ? Pupil pup;
? ? pup.setname("小明");
? ? pup.setage(15);
? ? pup.setscore(92.5f);
? ? pup.setranking(4);
? ? pup.sethobby("乒乓球");
? ? pup.display();
? ? return 0;
}
在派生類中訪問基類 private 成員的唯一方法就是借助基類的非 private 成員函數(shù),如果基類沒有非 private 成員函數(shù),
那么該成員在派生類中將無法訪問(除非使用下面講到的 using 關(guān)鍵字)
2.3 ?using改變權(quán)限
使用 using 關(guān)鍵字可以改變基類成員在派生類中的訪問權(quán)限,例如將 public 改為 private、將 protected 改為 public。
#include<iostream>
using namespace std;
//基類People
class People{
public:
? ? void show();
protected:
? ? char *m_name;
? ? int m_age;
};
void People::show(){
? ? cout<<m_name<<"的年齡是"<<m_age<<endl;
}
//派生類Student
class Student: public People{
public:
? ? void learning();
public:
? ? using People::m_name; ?//將procted改為public
? ? using People::m_age; ?//將procted改為public
? ? float m_score;
private:
? ? using People::show; ?//將public改為private
};
void Student::learning(){
? ? cout<<"我是"<<m_name<<",今年"<<m_age<<"歲,這次考了"<<m_score<<"分!"<<endl;
}
int main(){
? ? Student stu;
? ? stu.m_name = "小明";
? ? stu.m_age = 16;
? ? stu.m_score = 99.5f;
? ? stu.show(); ?//compile error
? ? stu.learning();
? ? return 0;
}
2.4 ?遮蔽
如果派生類中的成員(包括成員變量和成員函數(shù))和基類中的成員重名,那么就會遮蔽從基類繼承過來的成員。
所謂遮蔽,就是在派生類中使用該成員(包括在定義派生類時使用,也包括通過派生類對象訪問該成員)時,
實際上使用的是派生類新增的成員,而不是從基類繼承來的。
#include<iostream>
using namespace std;
//基類People
class People{
public:
? ? void show();
protected:
? ? char *m_name;
? ? int m_age;
};
void People::show(){
? ? cout<<"嗨,大家好,我叫"<<m_name<<",今年"<<m_age<<"歲"<<endl;
}
//派生類Student
class Student: public People{
public:
? ? Student(char *name, int age, float score);
public:
? ? void show(); ?//遮蔽基類的show()
private:
? ? float m_score;
};
Student::Student(char *name, int age, float score){
? ? m_name = name;
? ? m_age = age;
? ? m_score = score;
}
void Student::show(){
? ? cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<endl;
}
int main(){
? ? Student stu("小明", 16, 90.5);
? ? //使用的是派生類新增的成員函數(shù),而不是從基類繼承的
? ? stu.show();
? ? //使用的是從基類繼承來的成員函數(shù)
? ? stu.People::show();
? ? return 0;
}
2.5 ?基類和派生類遮蔽不構(gòu)成重載
基類成員函數(shù)和派生類成員函數(shù)不會構(gòu)成重載,如果派生類有同名函數(shù),
那么就會遮蔽基類中的所有同名函數(shù),不管它們的參數(shù)是否一樣。
#include<iostream>
using namespace std;
//基類Base
class Base{
public:
? ? void func();
? ? void func(int);
};
void Base::func(){ cout<<"Base::func()"<<endl; }
void Base::func(int a){ cout<<"Base::func(int)"<<endl; }
//派生類Derived
class Derived: public Base{
public:
? ? void func(char *);
? ? void func(bool);
};
void Derived::func(char *str){ cout<<"Derived::func(char *)"<<endl; }
void Derived::func(bool is){ cout<<"Derived::func(bool)"<<endl; }
int main(){
? ? Derived d;
? ? d.func("c.biancheng.net");
? ? d.func(true);
? ? d.func(); ?//compile error
? ? d.func(10); ?//compile error
? ? d.Base::func();
? ? d.Base::func(100);
? ? return 0;
}
2.6 ?派生類構(gòu)造函數(shù)
在派生類的構(gòu)造函數(shù)中調(diào)用基類的構(gòu)造函數(shù);
#include<iostream>
using namespace std;
//基類People
class People{
protected:
? ? char *m_name;
? ? int m_age;
public:
? ? People(char*, int);
};
People::People(char *name, int age): m_name(name), m_age(age){}
//派生類Student
class Student: public People{
private:
? ? float m_score;
public:
? ? Student(char *name, int age, float score);
? ? void display();
};
//People(name, age)就是調(diào)用基類的構(gòu)造函數(shù)
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
void Student::display(){
? ? cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<"。"<<endl;
}
int main(){
? ? Student stu("小明", 16, 90.5);
? ? stu.display();
? ? return 0;
}
構(gòu)造函數(shù)調(diào)用順序:先基類再派生類
****派生類構(gòu)造函數(shù)中只能調(diào)用直接基類的構(gòu)造函數(shù),不能調(diào)用間接基類的
2.7基類構(gòu)造函數(shù)調(diào)用規(guī)則
事實上,通過派生類創(chuàng)建對象時必須要調(diào)用基類的構(gòu)造函數(shù),這是語法規(guī)定。
換句話說,定義派生類構(gòu)造函數(shù)時最好指明基類構(gòu)造函數(shù);如果不指明,
就調(diào)用基類的默認(rèn)構(gòu)造函數(shù)(不帶參數(shù)的構(gòu)造函數(shù));如果沒有默認(rèn)構(gòu)造函數(shù),
那么編譯失敗。請看下面的例子:
#include <iostream>
using namespace std;
//基類People
class People{
public:
? ? People(); ?//基類默認(rèn)構(gòu)造函數(shù)
? ? People(char *name, int age);
protected:
? ? char *m_name;
? ? int m_age;
};
People::People(): m_name("xxx"), m_age(0){ }
People::People(char *name, int age): m_name(name), m_age(age){}
//派生類Student
class Student: public People{
public:
? ? Student();
? ? Student(char*, int, float);
public:
? ? void display();
private:
? ? float m_score;
};
Student::Student(): m_score(0.0){ } ?//派生類默認(rèn)構(gòu)造函數(shù)
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
void Student::display(){
? ? cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<"。"<<endl;
}
int main(){
? ? Student stu1;
? ? stu1.display();
? ? Student stu2("小明", 16, 90.5);
? ? stu2.display();
? ? return 0;
}
3。 派生類的析構(gòu)函數(shù)
和構(gòu)造函數(shù)類似,析構(gòu)函數(shù)也不能被繼承。
另外析構(gòu)函數(shù)的執(zhí)行順序和構(gòu)造函數(shù)的執(zhí)行順序也剛好相反:
創(chuàng)建派生類對象時,構(gòu)造函數(shù)的執(zhí)行順序和繼承順序相同,即先執(zhí)行基類構(gòu)造函數(shù),再執(zhí)行派生類構(gòu)造函數(shù)。
而銷毀派生類對象時,析構(gòu)函數(shù)的執(zhí)行順序和繼承順序相反,即先執(zhí)行派生類析構(gòu)函數(shù),再執(zhí)行基類析構(gòu)函數(shù)。
#include <iostream>
using namespace std;
class A{
public:
? ? A(){cout<<"A constructor"<<endl;}
? ? ~A(){cout<<"A destructor"<<endl;}
};
class B: public A{
public:
? ? B(){cout<<"B constructor"<<endl;}
? ? ~B(){cout<<"B destructor"<<endl;}
};
class C: public B{
public:
? ? C(){cout<<"C constructor"<<endl;}
? ? ~C(){cout<<"C destructor"<<endl;}
};
int main(){
? ? C test;
? ? return 0;
}
4。多繼承
例如已聲明了類A、類B和類C,那么可以這樣來聲明派生類D:
class D: public A, private B, protected C{
? ? //類D新增加的成員
}
多繼承下的構(gòu)造函數(shù)
多繼承形式下的構(gòu)造函數(shù)和單繼承形式基本相同,只是要在派生類的構(gòu)造函數(shù)中調(diào)用多個基類的構(gòu)造函數(shù)。
以上面的 A、B、C、D 類為例,D 類構(gòu)造函數(shù)的寫法為:
D(形參列表): A(實參列表), B(實參列表), C(實參列表){
? ? //其他操作
}
基類構(gòu)造函數(shù)的調(diào)用順序和和它們在派生類構(gòu)造函數(shù)中出現(xiàn)的順序無關(guān),而是和聲明派生類時基類出現(xiàn)的順序相同。
仍然以上面的 A、B、C、D 類為例,即使將 D 類構(gòu)造函數(shù)寫作下面的形式:
D(形參列表): B(實參列表), C(實參列表), A(實參列表){
? ? //其他操作
}
那么也是先調(diào)用 A 類的構(gòu)造函數(shù),再調(diào)用 B 類構(gòu)造函數(shù),最后調(diào)用 C 類構(gòu)造函數(shù)。
#include <iostream>
using namespace std;
//基類
class BaseA{
public:
? ? BaseA(int a, int b);
? ? ~BaseA();
protected:
? ? int m_a;
? ? int m_b;
};
BaseA::BaseA(int a, int b): m_a(a), m_b(b){
? ? cout<<"BaseA constructor"<<endl;
}
BaseA::~BaseA(){
? ? cout<<"BaseA destructor"<<endl;
}
//基類
class BaseB{
public:
? ? BaseB(int c, int d);
? ? ~BaseB();
protected:
? ? int m_c;
? ? int m_d;
};
BaseB::BaseB(int c, int d): m_c(c), m_d(d){
? ? cout<<"BaseB constructor"<<endl;
}
BaseB::~BaseB(){
? ? cout<<"BaseB destructor"<<endl;
}
//派生類
class Derived: public BaseA, public BaseB{
public:
? ? Derived(int a, int b, int c, int d, int e);
? ? ~Derived();
public:
? ? void show();
private:
? ? int m_e;
};
Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){
? ? cout<<"Derived constructor"<<endl;
}
Derived::~Derived(){
? ? cout<<"Derived destructor"<<endl;
}
void Derived::show(){
? ? cout<<m_a<<", "<<m_b<<", "<<m_c<<", "<<m_d<<", "<<m_e<<endl;
}
int main(){
? ? Derived obj(1, 2, 3, 4, 5);
? ? obj.show();
? ? return 0;
}
5。命名沖突
當(dāng)兩個或多個基類中有同名的成員時,如果直接訪問該成員,就會產(chǎn)生命名沖突,
編譯器不知道使用哪個基類的成員。這個時候需要在成員名字前面加上類名和域解析符::,
以顯式地指明到底使用哪個類的成員,消除二義性。
#include <iostream>
using namespace std;
//基類
class BaseA{
public:
? ? BaseA(int a, int b);
? ? ~BaseA();
public:
? ? void show();
protected:
? ? int m_a;
? ? int m_b;
};
BaseA::BaseA(int a, int b): m_a(a), m_b(b){
? ? cout<<"BaseA constructor"<<endl;
}
BaseA::~BaseA(){
? ? cout<<"BaseA destructor"<<endl;
}
void BaseA::show(){
? ? cout<<"m_a = "<<m_a<<endl;
? ? cout<<"m_b = "<<m_b<<endl;
}
//基類
class BaseB{
public:
? ? BaseB(int c, int d);
? ? ~BaseB();
? ? void show();
protected:
? ? int m_c;
? ? int m_d;
};
BaseB::BaseB(int c, int d): m_c(c), m_d(d){
? ? cout<<"BaseB constructor"<<endl;
}
BaseB::~BaseB(){
? ? cout<<"BaseB destructor"<<endl;
}
void BaseB::show(){
? ? cout<<"m_c = "<<m_c<<endl;
? ? cout<<"m_d = "<<m_d<<endl;
}
//派生類
class Derived: public BaseA, public BaseB{
public:
? ? Derived(int a, int b, int c, int d, int e);
? ? ~Derived();
public:
? ? void display();
private:
? ? int m_e;
};
Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){
? ? cout<<"Derived constructor"<<endl;
}
Derived::~Derived(){
? ? cout<<"Derived destructor"<<endl;
}
void Derived::display(){
? ? BaseA::show(); ?//調(diào)用BaseA類的show()函數(shù)
? ? BaseB::show(); ?//調(diào)用BaseB類的show()函數(shù)
? ? cout<<"m_e = "<<m_e<<endl;
}
int main(){
? ? Derived obj(1, 2, 3, 4, 5);
? ? obj.display();
? ? return 0;
}
6。虛繼承
多繼承時很容易產(chǎn)生命名沖突,
類 A 派生出類 B 和類 C,類 D 繼承自類 B 和類 C,
這個時候類 A 中的成員變量和成員函數(shù)繼承到類 D 中
變成了兩份,一份來自 A-->B-->D 這條路徑,另一份來自 A-->C-->D 這條路徑。
//間接基類A
class A{
protected:
? ? int m_a;
};
//直接基類B
class B: public A{
protected:
? ? int m_b;
};
//直接基類C
class C: public A{
protected:
? ? int m_c;
};
//派生類D
class D: public B, public C{
public:
? ? void seta(int a){ m_a = a; } ?//命名沖突
? ? void setb(int b){ m_b = b; } ?//正確
? ? void setc(int c){ m_c = c; } ?//正確
? ? void setd(int d){ m_d = d; } ?//正確
private:
? ? int m_d;
};
int main(){
? ? D d;
? ? return 0;
}
為了消除歧義,我們可以在 m_a 的前面指明它具體來自哪個類:
void seta(int a){ B::m_a = a; }
6.1 虛繼承
在繼承方式前面加上 virtual 關(guān)鍵字就是虛繼承:
//間接基類A
class A{
protected:
? ? int m_a;
};
//直接基類B
class B: virtual public A{ ?//虛繼承
protected:
? ? int m_b;
};
//直接基類C
class C: virtual public A{ ?//虛繼承
protected:
? ? int m_c;
};
//派生類D
class D: public B, public C{
public:
? ? void seta(int a){ m_a = a; } ?//正確
? ? void setb(int b){ m_b = b; } ?//正確
? ? void setc(int c){ m_c = c; } ?//正確
? ? void setd(int d){ m_d = d; } ?//正確
private:
? ? int m_d;
};
int main(){
? ? D d;
? ? return 0;
}
在虛繼承中,虛基類是由最終的派生類初始化的,換句話說,
最終派生類的構(gòu)造函數(shù)必須要調(diào)用虛基類的構(gòu)造函數(shù)。
對最終的派生類來說,虛基類是間接基類,而不是直接基類。
這跟普通繼承不同,在普通繼承中,派生類構(gòu)造函數(shù)中只能
調(diào)用直接基類的構(gòu)造函數(shù),不能調(diào)用間接基類的。
#include <iostream>
using namespace std;
//虛基類A
class A{
public:
? ? A(int a);
protected:
? ? int m_a;
};
A::A(int a): m_a(a){ }
//直接派生類B
class B: virtual public A{
public:
? ? B(int a, int b);
public:
? ? void display();
protected:
? ? int m_b;
};
B::B(int a, int b): A(a), m_b(b){ }
void B::display(){
? ? cout<<"m_a="<<m_a<<", m_b="<<m_b<<endl;
}
//直接派生類C
class C: virtual public A{
public:
? ? C(int a, int c);
public:
? ? void display();
protected:
? ? int m_c;
};
C::C(int a, int c): A(a), m_c(c){ }
void C::display(){
? ? cout<<"m_a="<<m_a<<", m_c="<<m_c<<endl;
}
//間接派生類D
class D: public B, public C{
public:
? ? D(int a, int b, int c, int d);
public:
? ? void display();
private:
? ? int m_d;
};
D::D(int a, int b, int c, int d): A(a), B(90, b), C(100, c), m_d(d){ }
void D::display(){
? ? cout<<"m_a="<<m_a<<", m_b="<<m_b<<", m_c="<<m_c<<", m_d="<<m_d<<endl;
}
int main(){
? ? B b(10, 20);
? ? b.display();
? ?
? ? C c(30, 40);
? ? c.display();
? ? D d(50, 60, 70, 80);
? ? d.display();
? ? return 0;
}
總結(jié)
以上是生活随笔為你收集整理的C++课堂笔记0716的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为云服务器不显示盘符,云服务器只有一个
- 下一篇: 003.节水马桶