《C++繼承詳解:從入門到理解公有、私有與保護繼承》
文章目錄
- 《C++繼承詳解:從入門到理解公有、私有與保護繼承》
- 一、繼承的概念及定義
- 1.1 繼承的概念
- 1.2 繼承定義
- 1.2.1 定義格式
- 1.2.2 繼承基類成員訪問方式的變化
- 1.3 繼承類模版
- 二、基類和派生類間的轉換
- 三、繼承中的作用域
- 3.1 隱藏規則
- 3.2 考察繼承作用域相關選擇題
- 四、派生類的默認成員函數
- 4.1 4個常見的默認成員函數
- 4.2 實現一個不能被繼承的類
- 五、繼承與友元
- 六、繼承與靜態成員
- 七、多繼承及其菱形繼承問題
- 7.1 繼承模型
- 7.2 虛繼承
- 7.3 IO庫中的菱形虛擬繼承
- 八、繼承和組合
- 九、整體源代碼
一、繼承的概念及定義
1.1 繼承的概念
1.2 繼承定義
1.2.1 定義格式
1.2.2 繼承基類成員訪問方式的變化
1.3 繼承類模版
繼承類模版就是繼承一個模版類,大框架和普通的繼承想吐,但是調用父類中的屬性或者行為時要指定在父類的哪個屬性或者行為,這樣是因為類模版的按需實例化,不指定就不會實例化,會報錯
下面是用繼承寫一個棧,這個棧繼承了父類vector
每次復用vector里面的成員函數時都要指定父類類域,否則報錯,找不到標識符
二、基類和派生類間的轉換
三、繼承中的作用域
3.1 隱藏規則
3.2 考察繼承作用域相關選擇題
四、派生類的默認成員函數
4.1 4個常見的默認成員函數
4.2 實現一個不能被繼承的類
五、繼承與友元
友元關系不能繼承,也就是說基類友元不能訪問派生類私有和保護成員
六、繼承與靜態成員
基類定義了static靜態成員,則整個繼承體系里面只有一個這樣的成員。無論派生出多少個派生類,都只有一個static成員實例
七、多繼承及其菱形繼承問題
7.1 繼承模型
單繼承和多繼承
菱形繼承: 會出現 二義性 和 數據冗余 的問題
7.2 虛繼承
為了解決菱形繼承的兩個問題,這里使用虛繼承,也就是在開始繼承相同的基類的派生類后面加上virtual再加繼承方式和基類
我們可以設計出多繼承,但是不建議設計出菱形繼承,因為菱形虛擬繼承以后,無論是使用還是底層都會復雜很多。當然有多繼承語法支持,就一定存在會設計出菱形繼承,像Java是不支持多繼承的,就避開了菱形繼承
7.3 IO庫中的菱形虛擬繼承
八、繼承和組合
九、整體源代碼
代碼如下(示例):
#include<iostream>
using namespace std;//class Student
//{
//public:
// // 進?校園/圖書館/實驗室刷?維碼等?份認證
// void identity()
// {
// // ...
// }
// // 學習
// void study()
// {
// // ...
// }
//protected:
// string _name = "peter"; // 姓名
// string _address; // 地址
// string _tel; // 電話
// int _age = 18; // 年齡
// int _stuid; // 學號
//};
//class Teacher
//{
//public:
// // 進?校園/圖書館/實驗室刷?維碼等?份認證
// void identity()
// {
// // ...
// }
// // 授課
// void teaching()
// {
// //...
// }
//protected:
// string _name = "張三"; // 姓名
// int _age = 18; // 年齡
// string _address; // 地址
// string _tel; // 電話
// string _title; // 職稱
//};
//int main()
//{
// return 0;
//}//class Person
//{
//public:
// // 進?校園/圖書館/實驗室刷?維碼等?份認證
// void identity()
// {
// cout << "void identity()" << _name << endl;
// }
//protected:
// string _name = "張三"; // 姓名
// string _address; // 地址
// string _tel; // 電話
// int _age = 18; // 年齡
//};
//class Student : public Person
//{
//public:
// // 學習
// void study()
// {
// // ...
// }
//protected:
// int _stuid; // 學號
//};
//class Teacher : public Person
//{
//public:
// // 授課
// void teaching()
// {
// //...
// }
//protected:
// string title; // 職稱
//};
//int main()
//{
// Student s;
// Teacher t;
// s.identity();
// t.identity();
// return 0;
//}// 實例演?三種繼承關系下基類成員的各類型成員訪問關系的變化
//class Person
//{
//public:
// void Print()
// {
// cout << _name << endl;
// }
//protected:
// string _name; // 姓名
//private:
// int _age; // 年齡
//};
//
////class Student : protected Person
////class Student : private Person
//class Student : public Person
//{
//protected:
// int _stunum; // 學號
//};#include<vector>
#include<stack>
//namespace ming
//{//template<class T>//class vector//{};// stack和vector的關系,既符合is-a,也符合has-a
// template<class T>
// class stack : public std::vector<T>
// {
// public:
// void push(const T& x)
// {
// // 基類是類模板時,需要指定?下類域,
// // 否則編譯報錯:error C3861: “push_back”: 找不到標識符
// // 因為stack<int>實例化時,也實例化vector<int>了
//// 但是模版是按需實例化,push_back等成員函數未實例化,所以找不到
// vector<T>::push_back(x);
// //push_back(x);
// }
// void pop()
// {
// vector<T>::pop_back();
// }
// const T& top()
// {
// return vector<T>::back();
// }
// bool empty()
// {
// return vector<T>::empty();
// }
// };
//}
//int main()
//{
// ming::stack<int> st;
// st.push(1);
// st.push(2);
// st.push(3);
// while (!st.empty())
// {
// cout << st.top() << " ";
// st.pop();
// }
// return 0;
//}
//
//class Person
//{
//protected:
// string _name; // 姓名
// string _sex; // 性別
// int _age; // 年齡
//};
//class Student : public Person
//{
//public:
// int _No; // 學號
//};
//int main()
//{
// Student sobj;
// // 1.派?類對象可以賦值給基類的指針/引?
// Person* pp = &sobj;
// Person& rp = sobj;
// // ?類對象可以賦值給基類的對象是通過調?后?會講解的基類的拷?構造完成的
// Person pobj = sobj;
// //2.基類對象不能賦值給派?類對象,這?會編譯報錯
// sobj = pobj;
// return 0;
//}// Student的_num和Person的_num構成隱藏關系,可以看出這樣代碼雖然能跑,但是?常容易混淆
//class Person
//{
//protected:
// string _name = "?李?"; // 姓名
// int _num = 111; // ?份證號
//};
//class Student : public Person
//{
//public:
// void Print()
// {
// cout << " 姓名:" << _name << endl;
// cout << " ?份證號:" << Person::_num << endl;
// cout << " 學號:" << _num << endl;
// }
//protected:
// int _num = 999; // 學號
//};
//int main()
//{
// Student s1;
// s1.Print();
// return 0;
//};
//
//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;
//};//class Person
// {
//public:
// Person(const char* name = "peter")
// : _name(name)
// {
// cout << "Person()" << endl;
// }
// Person(const Person& p)
// : _name(p._name)
// {
// cout << "Person(const Person& p)" << endl;
// }
// Person& operator=(const Person& p)
// {
// cout << "Person operator=(const Person& p)" << endl;
// if (this != &p)
// _name = p._name;
// return *this;
// }
// ~Person()
// {
// cout << "~Person()" << endl;
// }
// protected:
// string _name; // 姓名
//};
//class Student : public Person
//{
//public:
// Student(const char* name, int num)
// : Person(name)
// , _num(num)
// {
// cout << "Student()" << endl;
// }
// Student(const Student& s)
// : Person(s)
// , _num(s._num)
// {
// cout << "Student(const Student& s)" << endl;
// }
// Student& operator = (const Student& s)
// {
// cout << "Student& operator= (const Student& s)" << endl;
// if (this != &s)
// {
// // 構成隱藏,所以需要顯?調?
// Person::operator =(s);
// _num = s._num;
// }
// return *this;
// }
// ~Student()
// {
// cout << "~Student()" << endl;
// }
//protected:
// int _num; //學號
//};
//int main()
//{
// Student s1("jack", 18);
// Student s2(s1);
// Student s3("rose", 17);
// s1 = s3;
// return 0;
//}// C++98
//class Person
//{
//private:
// Person(string name = "Peter")
// :_name(name)
// {}
//};
//
//// C++11
//class Person final
//{
//public:
// Person(string name = "Peter")
// :_name(name)
// {}
// ~Person()
// {
// cout << "基類析構" << endl;
// }
//};
//
//class Student;
//class Person
//{
//public:
// friend void Display(const Person& p, const Student& s);
//protected:
// string _name; // 姓名
//};
//class Student : public Person
//{
//protected:
// int _stuNum; // 學號
//};
//void Display(const Person& p, const Student& s)
//{
// cout << p._name << endl;
// cout << s._stuNum << endl;
//}
//int main()
//{
// Person p;
// Student s;
// // 編譯報錯:error C2248: “Student::_stuNum”: ?法訪問 protected 成員
// // 解決?案:Display也變成Student 的友元即可
// Display(p, s);
// return 0;
//}//class Person
//{
//public:
// string _name;
// static int _count;
//};
//int Person::_count = 0;
//class Student : public Person
//{
//protected:
// int _stuNum;
//};
//int main()
//{
// Person p;
// Student s;
// // 這?的運?結果可以看到?靜態成員_name的地址是不?樣的
// // 說明派?類繼承下來了,?派?類對象各有?份
// cout << &p._name << endl;
// cout << &s._name << endl;
// // 這?的運?結果可以看到靜態成員_count的地址是?樣的
// // 說明派?類和基類共?同?份靜態成員
// cout << &p._count << endl;
// cout << &s._count << endl;
// // 公有的情況下,?派?類指定類域都可以訪問靜態成員
// cout << Person::_count << endl;
// cout << Student::_count << endl;
// return 0;
//}//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()
//{
// // 編譯報錯:error C2385: 對“_name”的訪問不明確
// Assistant a;
// a._name = "peter";
// // 需要顯?指定訪問哪個基類的成員可以解決?義性問題,但是數據冗余問題?法解決
// a.Student::_name = "xxx";
// a.Teacher::_name = "yyy";
// return 0;
//}//class Person
//{
//public:
// string _name; // 姓名
// /*int _tel;
// * int _age;
//string _gender;
//string _address;*/
//// ...
//};
//// 使?虛繼承Person類
//class Student : virtual public Person
//{
//protected:
// int _num; //學號
//};
//// 使?虛繼承Person類
//class Teacher : virtual public Person
//{
//protected:
// int _id; // 職?編號
//};
//// 教授助理
//class Assistant : public Student, public Teacher
//{
//protected:
// string _majorCourse; // 主修課程
//};
//int main()
//{
// // 使?虛繼承,可以解決數據冗余和?義性
// Assistant a;
// a._name = "peter";
// return 0;
//}class Person
{
public:Person(const char* name):_name(name){}string _name; // 姓名
};
class Student : virtual public Person
{
public:Student(const char* name, int num):Person(name), _num(num){}
protected:int _num; //學號
};
class Teacher : virtual public Person
{
public:Teacher(const char* name, int id):Person(name), _id(id){}
protected:int _id; // 職?編號
};
// 不要去玩菱形繼承
class Assistant : public Student, public Teacher
{
public:Assistant(const char* name1, const char* name2, const char* name3):Person(name3), Student(name1, 1), Teacher(name2, 2){}
protected:string _majorCourse; // 主修課程
};
int main()
{// 思考?下這?a對象中_name是"張三", "李四", "王五"中的哪?個?Assistant a("張三", "李四", "王五");return 0;
}template<class CharT, class Traits = std::char_traits<CharT>>
class basic_ostream : virtual public std::basic_ios<CharT, Traits>
{};
template<class CharT, class Traits = std::char_traits<CharT>>
class basic_istream : virtual public std::basic_ios<CharT, Traits>
{};// Tire(輪胎)和Car(?)更符合has-a的關系
class Tire {
protected:string _brand = "Michelin"; // 品牌size_t _size = 17; // 尺?
};
class Car {
protected:string _colour = "??"; // 顏?string _num = "陜ABIT00"; // ?牌號Tire _t1; // 輪胎Tire _t2; // 輪胎Tire _t3; // 輪胎Tire _t4; // 輪胎
};
class BMW : public Car {
public:void Drive() { cout << "好開-操控" << endl; }
};
// Car和BMW/Benz更符合is-a的關系
class Benz : public Car {
public:void Drive() { cout << "好坐-舒適" << endl; }
};
template<class T>
class vector
{};
// stack和vector的關系,既符合is-a,也符合has-a
template<class T>
class stack : public vector<T>
{};
template<class T>
class stack
{
public:vector<T> _v;
};
int main()
{return 0;
}