網(wǎng)站做ulr跳轉(zhuǎn)網(wǎng)絡(luò)銷售好做嗎
目錄
一、繼承的概念
二、基類和派生類對(duì)象賦值轉(zhuǎn)換
三、繼承的作用域
四、派生類的默認(rèn)成員函數(shù)
五、繼承與友元
六、繼承與靜態(tài)成員變量
七、菱形繼承與虛擬繼承
一、繼承的概念
繼承是指一個(gè)類可以通過繼承獲得另一個(gè)類的屬性和方法,擴(kuò)展自己的功能,提高了代碼的復(fù)用性,增加了類與類之間的耦合性。
繼承機(jī)制允許程序員在保持原有類特性的基礎(chǔ)上進(jìn)行擴(kuò)展,增加功能,產(chǎn)生新的派生類。
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;class Person
{
public:void Print(){cout << "name: " << _name << ", " << "age: " << _age << endl;}private:string _name = "unknow";int _age = 0;
};class Student : public Person
{
private:string _stuID = "";
};class Teacher : public Person
{
private:string _jobID = "";
};int main()
{Student s;Teacher t;cout << typeid(s).name() << endl;cout << typeid(t).name() << endl;s.Print();t.Print();return 0;
}
類成員 / 繼承方式 | public繼承 | protect繼承 | private繼承 |
基類的public成員 | 派生類的public成員 | 派生類的protect成員 | 派生類的private成員 |
基類的protect成員 | 派生類的protect成員 | 派生類的protect成員 | 派生類的private成員 |
基類的private成員 | 派生類中不可見 | 派生類中不可見 | 派生類中不可見 |
由上表可見,類的繼承遵循權(quán)限縮小原則,與函數(shù)傳參類似。
二、基類和派生類對(duì)象賦值轉(zhuǎn)換
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;class Person
{
protected:string _name; // 姓名string _sex; // 性別int _age; // 年齡
};class Student : public Person
{
public:int _No; // 學(xué)號(hào)
};void Test()
{Student sobj;// 1.子類對(duì)象可以賦值給父類對(duì)象/指針/引用Person pobj = sobj;Person* pp = &sobj;Person& rp = sobj;//2.基類對(duì)象不能賦值給派生類對(duì)象sobj = pobj;// 3.基類的指針可以通過強(qiáng)制類型轉(zhuǎn)換賦值給派生類的指針pp = &sobj;Student* ps1 = (Student*)pp; // 這種情況轉(zhuǎn)換時(shí)可以的。ps1->_No = 10;pp = &pobj;Student* ps2 = (Student*)pp; // 這種情況轉(zhuǎn)換時(shí)雖然可以,但是會(huì)存在越界訪問的問題ps2->_No = 10;
}
三、繼承的作用域
在繼承體系中基類和派生類都有獨(dú)立的作用域,子類和父類中有同名成員,子類成員將屏蔽父類對(duì)同名成員的直接訪問,這種情況叫隱藏,也叫重定義。(在子類成員函數(shù)中,可以使用 基類::基類成員 顯示訪問)。
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;// Student的_num和Person的_num構(gòu)成隱藏關(guān)系,可以看出這樣代碼雖然能跑,但是非常容易混淆
class Person
{
protected:string _name = "小李子"; // 姓名int _num = 111; // 身份證號(hào)
};class Student : public Person
{
public:void Print(){cout << " 姓名:" << _name << endl;cout << " 身份證號(hào):" << Person::_num << endl;cout << " 學(xué)號(hào):" << _num << endl;}protected:int _num = 999; // 學(xué)號(hào)
};int main()
{Student s1;s1.Print();
};
四、派生類的默認(rèn)成員函數(shù)
派生類對(duì)象初始化先調(diào)用基類構(gòu)造再調(diào)派生類構(gòu)造。
派生類對(duì)象析構(gòu)清理先調(diào)用派生類析構(gòu)再調(diào)基類的析構(gòu)
派生類的拷貝構(gòu)造函數(shù)必須調(diào)用基類的拷貝構(gòu)造完成基類的拷貝初始化。
派生類的operator=必須要調(diào)用基類的operator=完成基類的復(fù)制。
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;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; //學(xué)號(hào)
};int main()
{Student s1("jack", 18);Student s2(s1);Student s3("rose", 17);s1 = s3;
}/*
Person()
Student()
Person(const Person& p)
Student(const Student& s)
Person()
Student()
Student& operator= (const Student& s)
Person operator=(const Person& p)
~Student()
~Person()
~Student()
~Person()
~Student()
~Person()
*/
五、繼承與友元
友元函數(shù)定義在類外部,可以訪問類的私有成員和保護(hù)成員。
友元關(guān)系不能繼承,也就是說基類友元不能訪問子類私有和保護(hù)成員。
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;#define _CRT_SECURE_NO_WARNINGS 1class Student;class Person
{
public:friend void Display(const Person& p, const Student& s);
protected:string _name; // 姓名
};class Student : public Person
{
protected:int _stuNum; // 學(xué)號(hào)
};void Display(const Person& p, const Student& s)
{cout << p._name << endl;cout << s._stuNum << endl; // 無法訪問
}void main()
{Person p;Student s;Display(p, s);
}
六、繼承與靜態(tài)成員變量
基類定義了static靜態(tài)成員,則整個(gè)繼承體系里面只有一個(gè)這樣的成員。無論派生出多少個(gè)子類,都只有一個(gè)static成員實(shí)例 。
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;#define _CRT_SECURE_NO_WARNINGS 1class Person
{
public:Person() { ++_count; }
protected:string _name; // 姓名
public:static int _count; // 統(tǒng)計(jì)人的個(gè)數(shù)。
};// 靜態(tài)成員在類外部賦值
int Person::_count = 0;class Student : public Person
{
protected:int _stuNum; // 學(xué)號(hào)
};class Graduate : public Student
{
protected:string _seminarCourse; // 研究科目
};void main()
{Student s1;Student s2;Student s3;Graduate s4;cout << " 人數(shù) :" << Person::_count << endl;Student::_count = 0;cout << " 人數(shù) :" << Person::_count << endl;
}
七、菱形繼承與虛擬繼承
菱形繼承是多繼承的一種特殊情況,但是菱形繼承有數(shù)據(jù)冗余和二義性的問題。
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;#define _CRT_SECURE_NO_WARNINGS 1
class Person
{
public:string _name; // 姓名
};class Student : public Person
{
protected:int _num; //學(xué)號(hào)
};class Teacher : public Person{
protected:int _id; // 職工編號(hào)
};class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修課程
};void main()
{// 這樣會(huì)有二義性無法明確知道訪問的是哪一個(gè)Assistant a;a._name = "peter"; // 報(bào)錯(cuò),Assisitant::_name 不明確// 需要顯示指定訪問哪個(gè)父類的成員可以解決二義性問題,但是數(shù)據(jù)冗余問題無法解決a.Student::_name = "xxx";a.Teacher::_name = "yyy";
}
虛擬繼承可以解決菱形繼承的二義性和數(shù)據(jù)冗余的問題。如上面的繼承關(guān)系,在Student和Teacher的繼承Person時(shí)使用虛擬繼承,即可解決問題。需要注意的是,虛擬繼承不要在其他地方去使用。
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
using namespace std;#define _CRT_SECURE_NO_WARNINGS 1
class Person
{
public:string _name; // 姓名
};class Student : virtual public Person
{
protected:int _num; //學(xué)號(hào)
};class Teacher : virtual public Person{
protected:int _id; // 職工編號(hào)
};class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修課程
};void main()
{// 這樣會(huì)有二義性無法明確知道訪問的是哪一個(gè)Assistant a;a._name = "peter"; // 報(bào)錯(cuò),Assisitant::_name 不明確// 需要顯示指定訪問哪個(gè)父類的成員可以解決二義性問題,但是數(shù)據(jù)冗余問題無法解決a.Student::_name = "xxx";a.Teacher::_name = "yyy";
}
虛繼承會(huì)維護(hù)一張?zhí)摶?#xff0c;每個(gè)虛成員函數(shù)的類都指向虛基表的指針,通過虛基表中存儲(chǔ)的偏移量找到公共父類的成員變量。