摘要:基類中的構造函數和析構函數不能被繼承,在派生類中需要定義新的構造函數和析構函數,私有成員不能被繼承。對象訪問在派生類外部,通過派生類的對象對從基類繼承來的成員的訪問。
1、類與類之間的關系有哪些?
與類之間的關系分為縱向和橫向兩種:
縱向就是繼承;橫向包括:依賴、關聯、聚合和組合。(這里不進行解釋,詳解鏈接:https://blog.csdn.net/u014694510/article/details/88316605.
2、什么是繼承?繼承有什么作用?
所謂繼承就是從先輩出得到屬性和行為特征。類的繼承就是新的類從已有類那里得到已有的特征;從另一個角度來看,類的繼承和派生機制使程序員無需修改已有類,只需在此類的基礎上,通過少量代碼或修改少量代碼的方法得到新的類,從而很好的解決了代碼重用的問題。由已有類產生新類時,新類便包含了已有類的特征,同時也可以加入自己的新特征。已有類被稱為基類或者父類,產生的新類被稱為派生類或者子類。
3、繼承有哪些分類?
派生類的繼承方式有私有繼承(private),公有繼承(public),保護繼承(protect)
4、基類成員在派生類的訪問屬性是怎樣的?
基類中的成員 | 在公有派生類的訪問屬性 | 在私有派生類中的訪問屬性 | 在保護派生類中的訪問屬性 |
---|---|---|---|
私有成員 | 不可直接訪問 | 不可直接訪問 | 不可直接訪問 |
公有成員 | 公有 | 私有 | 保護 |
保護成員 | 保護 | 私有 | 保護 |
5、基類的成員函數都能被繼承嗎?
不是。基類中的構造函數和析構函數不能被繼承,在派生類中需要定義新的構造函數和析構函數,私有成員不能被繼承。
6、派生類對基類成員的訪問規則是怎樣的?
內部訪問:由派生類中新增的成員函數對基類繼承來的成員的訪問。
對象訪問:在派生類外部,通過派生類的對象對從基類繼承來的成員的訪問。
私有繼承的訪問規則:
基類中的成員 | 私有成員 | 公有成員 | 保護成員 |
---|---|---|---|
內部訪問 | 不可訪問 | 可訪問 | 可訪問 |
對象訪問 | 不可訪問 | 不可訪問 | 不可訪問 |
公有繼承的訪問規則:
基類中的成員 | 私有成員 | 公有成員 | 保護成員 |
---|---|---|---|
內部訪問 | 不可訪問 | 可訪問 | 可訪問 |
對象訪問 | 不可訪問 | 可訪問 | 不可訪問 |
保護成員的訪問規則:
基類中的成員 | 私有成員 | 公有成員 | 保護成員 |
---|---|---|---|
內部訪問 | 不可訪問 | 可訪問 | 可訪問 |
對象訪問 | 不可訪問 | 不可訪問 | 不可訪問 |
先看個簡單的代碼了解一下:
class Person{public: void work() { cout << "work()" << endl; } void eat() { cout << "eat()" << endl; }protected:private: string _name; int _age; string _sex;};class Student :public Person{public: void show() { cout << _name << endl; cout << _age << endl; cout << _sex << endl; }};
這里會報錯:
但如果把這些私有屬性改為保護或者公有的話就不會報錯:
class Person{public: void work() { cout << "work()" << endl; } void eat() { cout << "eat()" << endl; }protected: string _name; int _age; string _sex;private:};class Student :public Person{public: void show() { cout << _name << endl; cout << _age << endl; cout << _sex << endl; }};
這就是因為私有成員不可以被繼承。
總結:子類繼承的父類成員,在自身中的權限不能高于繼承權限()
再看這個代碼:
class Person{public: Person(string name,int age,string sex,string wife=string()) { _name=name; _age=age; _sex=sex; _wife=wife; } ~Person() { cout<<"~Person()"<<endl; } void work() { cout << "work()" << endl; } void eat() { cout << "eat()" << endl; }protected: string _name; int _age; string _sex;private: string wife;};class Student :public Person{public: void show() { cout << _name << endl; cout << _age << endl; cout << _sex << endl; }};int main(){ Student s;//報錯,無法引用默認的構造函數 s.show();}
這樣改正之后錯誤消失(給派生類定義構造函數):
class Student :public Person{public: Student(string name, int age, string sex, string num, string wife = string()) :Person(name,age,sex,wife) { cout << "Student(string name, int age, string sex, string num, string wife = string())" << endl; _num = num; } void show() { cout << _name << endl; cout << _age << endl; cout << _sex << endl; cout << _num << endl; }private: string _num;};int main(){ Student s("zjh",11,"man","1111"); s.show();}
錯誤原因:C++規定,當基類的構造函數沒有參數,或沒有顯示定義構造函數時,派生類可以不向基類傳遞參數,甚至可以不定義構造函數。當基類含有帶參數的構造函數時,派生類必須定義構造函數,以提供把參數傳遞給構造函數的途徑。
7、派生類構造函數和析構函數的執行順序是怎樣的?
通常情況下,當創建派生類對象時,首先執行基類的構造函數,隨后再執行派生類的構造函數;當撤銷派生類對象時,則先執行派生類的析構函數,隨后再執行基類的析構函數。
8、派生類構造函數的參數列表是怎樣構成的?
Student(string name, int age, string sex, string num, string wife = string()) :Person(name,age,sex,wife)
從上面列出的派生類Student
構造函數首行中可以看到,派生類構造函數名后邊括號內的總參數表中包括了參數的類型和參數名,而基類構造函數參數表中只有參數名而不包括參數類型,因為在這里不是定義基類構造函數,而是調用基類構造函數
(這里的調用和在主函數中的調用是一樣的,只是為了說明這部分參數需要用基類的構造函數初始化),因此這些參數是實參而不是形參。它們可以是派生類構造函數總參數列表中的參數,也可以是常量和全局變量。
9、如果有多層繼承,參數列表又怎樣構成?
這里我們給上邊的Student
類再寫一個派生類來看看
class High_Student :public Student{public: High_Student(string name, int age, string sex, string num, string high, string wife = string()) :Student(name, age, sex, num,wife) { cout << "High_Student()" << endl; _high = high; } ~High_Student() { cout<<"High_Student()"<<endl; }protected:private: string _high;};int main(){ High_Student a = { "zjh",21,"nan","1010","sss","aaa"}; a.eat(); return 0;}
我們可以看出,這里依舊是類名后邊是總參數列表,但是冒號后邊是前兩個父類的實參,我們可以將Student(name, age, sex, num,wife)
理解為嵌套調用,即執行該語句之后,還是先調用Person
類的構造函數初始化name、sge、sex、wife
四個參數,再調用Student
類的構造函數初始化num
.
10、C++中的隱藏是怎樣的?
還是先看代碼:
class Base{public: void fun1(int a) { cout << "Base::void fun1()" << endl; }protected:private: int _a;};class Derive :public Base{public: void fun1() { fun1(10);//這里會報錯 cout << "Derive::void fun1()"<<endl; } void fun1(int a,int b) { cout << "Derive::void fun1(int a)" << endl; }protected:private: int _b;};int main(){ Derive d; d.fun1(10);//這里會報錯,顯示沒有匹配的函數}
問題:明明子類繼承了父類只有一個參數的構造函數,為什么還不能用?
C++中規定,當父類和子類有同名參數時,子類會隱藏父類的同名函數,導致子類對象和子類成員函數不能調用。
解決辦法:d.Base::fun1();
Base::fun1()
給函數加作用域
接下來我們再看一段代碼,通過這段代碼引出虛基類的概念:
class Base{public: Base() { a = 5; cout << "Base()" << endl; }protected: int a;};class Base1 :public Base{public: int b1; Base1() { a = a + 10; cout << "Base1()" << endl; }};class Base2 :public Base{public: int b2; Base2() { a = a + 20; cout << "Base2()" << endl; }};class Derive :public Base1, public Base2{public: int d; Derive() { cout<<"Derive a="<<a<<endl;//會報錯 }};int main(){ Derive d; return 0;}
上邊報錯語句需要改成這樣才能成功運行:
cout << "Base1::a=" << Base1::a << endl; cout << "Base2::a=" << Base2::a << endl;
執行結果如下:
11、為什么這里加上作用域就能成功運行?
在上述程序中,類Derive
是從類Base1和Base2
公有派生來的,而類Base1和Base2又
都是從類Base
公有派生而來的。雖然在類Base1和Base2
中沒有定義數據成員a
,但是它們分別都從類Base
繼承了數據成員a
,這樣在類Base1和Base2
中同時存在著數據成員a
,它們都是類Base
成員的復制。但是類Base1和Base2
中的數據成員a
具有不同的存儲單元,可以存放不同的數據。在程序中可以通過類Base1和Base2
去調用基類Base
的構造函數,分別對類Base1和Base2
的數據成員a
初始化。因此在Derive
的構造函數中輸出a
的值,必須加上類名,指出是哪一個數據成員a
,否則就會出現二義性。(即類中的數據成員a
的值可能是Base1
中的a
,也可能是Base2
中的a
)。
圖解:
為了解決這個問題,從而有了虛基類:
先看圖解,了解虛基類是怎樣解決的
虛基類的本質其實就是:當基類通過多條派生路徑被一個派生類繼承時,該派生類只繼承該基類一次,也就是說,基類成員只保留一次。
下面來看代碼:
class Base{public: Base() { a = 5; cout << "Base()a=" <<a<< endl; }protected: int a;};class Base1 :virtual public Base{public: int b1; Base1() { a = a + 10; cout << "Base1()a=" <<a<< endl; }};class Base2 :virtual public Base{public: int b2; Base2() { a = a + 20; cout << "Base2()a=" <<a<< endl; }};class Derive :public Base1, public Base2{public: int d; Derive() { cout << "Derive a=" << a << endl; }};int main(){ Derive d; return 0;}
執行結果如下:
關于虛基類初始化的幾點說明:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/125337.html
摘要:上面需要了解的是這倆個版本都是破蛹成蝶的版本世界挑戰榜咋才前三還沒擠進去呀,你想想世界上有幾千中編程語言,在其中脫穎出來,可以說是天之嬌子,鳳毛麟角了。支持正版圖靈上面買吧,如果沒錢買盜版吧學完以后買本正版支持一下,創作不易是吧 ...
摘要:也就是說,一個實例變量,在的對象初始化過程中,最多可以被初始化次。當所有必要的類都已經裝載結束,開始執行方法體,并用創建對象。對子類成員數據按照它們聲明的順序初始化,執行子類構造函數的其余部分。 類的拷貝和構造 C++是默認具有拷貝語義的,對于沒有拷貝運算符和拷貝構造函數的類,可以直接進行二進制拷貝,但是Java并不天生支持深拷貝,它的拷貝只是拷貝在堆上的地址,不同的變量引用的是堆上的...
摘要:繼承繼承,就是子類繼承父親的特征和行為,使得子類具有父類的成員變量和方法。此時,被繼承的類稱為父類或基類,而繼承的類稱為子類或派生類。,如果存在繼承關系的時候,和就不一樣了基類中的成員可以在派生類中使用,但是基類中的成員不能再派生類中使用。 ...
摘要:月日,發布文章,介紹了年游戲項目的十大編程語言。無疑是游戲項目的最佳編程語言之一。是和等游戲引擎所使用的主要編程語言。對于游戲開發者來說,是最友好最靈活的編程語言之一。作為游戲項目的最佳視頻游戲編程語言之一,正在贏得屬于自己的一份榮耀。 ...
閱讀 3792·2023-01-11 11:02
閱讀 4299·2023-01-11 11:02
閱讀 3121·2023-01-11 11:02
閱讀 5231·2023-01-11 11:02
閱讀 4793·2023-01-11 11:02
閱讀 5568·2023-01-11 11:02
閱讀 5371·2023-01-11 11:02
閱讀 4070·2023-01-11 11:02