//C++学习笔记_04抽象类、多态 (多重继承的歧义性问题 和 virtual虚继承) #include<cstring> #include<cstdio> #include<iostream> using namespace std; class CBase { public: //我们的类,一定至少要有一个构造函数 //如果不定义构造函数,系统会自动生成一个空的构造函数(构造函数内不做任何事情) //同样的,如果不定义析构函数,系统会自动生成一个空的析构函数(构造函数内不做任何事情) //CBase(); //如果我们没有定义无参的构造函数(默认构造函数),我们定义了其他构造函数,则不会再生成默认构造函数来 CBase(int x); ~CBase(); void Print(); }; /* CBase::CBase(){cout << "构造 CBase..." << endl;} */ CBase::CBase(int x) {cout << "构造 CBase..." << x << endl;} CBase::~CBase() {cout << "析构 CBase..." << endl;} void CBase::Print() {cout << "I am CBase..." << endl;} class CSuper { public: CSuper(); ~CSuper(); void Print(); }; CSuper::CSuper() {cout << "构造 CSuper..." << endl;} CSuper::~CSuper() {cout << "析构 CSuper..." << endl;} void CSuper::Print() {cout << "I am CSuper..." << endl;} //我们的子类,在构造的时候,会自动调用父类的默认构造函数 //如果父类,没有定义构造函数-->不会有问题,因为会自动生成一个 //如果父类,定义了构造函数,但不是默认构造函数 (定义的这个构造函数带参数) // --》子类构造的时候会出错 (找不到父类的默认构造函数) //解决方式: // 1:给父类定义默认构造函数(无参的) // 2:构造子类的时候,显示的指定调用那个父类的构造函数,加上 :CBase(1) class Derived :public CBase, public CSuper { public: Derived(); ~Derived(); void Print(); }; Derived::Derived() :CBase(1) {cout << "构造 Derived..." << endl;} Derived::~Derived() {cout << "析构 Derived..." << endl;} void Derived::Print() {cout << "I am Derived..." << endl;} void TestBase() { //CBase B1(1); Derived D1; //D1 调用Print() 函数,两个父类都定义了,无法确认调用哪一个 //--》显示指定调用哪个, 使用 CBase:: 指定函数的作用域 //D1.Print(); D1.CBase::Print(); D1.CSuper::Print(); //当然,如果我们自己定义了 Print,那么就可以直接调用了 D1.Print(); } class AAA:virtual public CSuper { public: AAA(); }; AAA::AAA(){cout << "构造AAA" << endl;} class BBB :virtual public CSuper { public: BBB(); }; BBB::BBB(){cout << "构造BBB" << endl;} class CCC :public AAA, public BBB { public: CCC(); }; CCC::CCC(){cout << "构造CCC" << endl;} void TestDiamondInherit() { //构造 C1 先构造 AAA, 然后构造 BBB, 最后构造 CCC // 在构造 AAA的时候,又需要先构造AAA的父类 CSuper, 然后才构造BBB // 在构造 BBB的时候,又需要先构造BBB的父类 CSuper, 然后才构造BBB //--》构造顺序:CSuper --> AAA --> CSuper -->BBB --> CCC CCC C1; //==》 上面有个问题:CSuper 会被重复构造,冗余 //--》解决方式:中间层 AAA 和 BBB 继承 CSuper的时候,定义为虚继承 //class AAA :virtual public CSuper //class BBB :virtual public CSuper //虚继承后,CSuper 被 AAA 和BBB共用,被构造一次后,不会重复构造 } int main() { //TestBase(); TestDiamondInherit(); //system("pause"); return 0; }
//C++学习笔记_04抽象类、多态 (菱形继承) #include <cstdio> #include <cstring> #include <iostream> using namespace std; class CPerson { private: char name[16]; protected: //对象不能直接访问,但是允许子类中的成员函数进行访问 unsigned int age; public: CPerson(); CPerson(char szName[], unsigned int uiAge); ~CPerson(); void Print(); }; CPerson::CPerson(){} CPerson::CPerson(char szName[], unsigned int uiAge){ //cout << "构造 CPerson..." << endl; strcpy(name,szName); age = uiAge; } CPerson::~CPerson(){} void CPerson::Print(){ cout << "姓名 :" << name << endl; cout << "年龄 :" << age << endl; } //CWorker 继承 CPerson: 也就是说,不需要重写 某些函数或者变量 //无论什么继承方式,父类的 private 成员,子类不允许访问 //对于父类的 public 成员,和 protected成员: //public 表示公有继承方式:父类的成员,访问权限不变 (不降权) //private 表示私有继承: 父类的成员,相当于子类的 私有成员 (降权) //protected 表示保护继承: 父类的成员,相当于子类的 protected成员(降权) class CWorker:public CPerson { private: char company[20]; //公司 public: CWorker(char szName[], unsigned int uiAge, char szCompany[]); ~CWorker(); void Carry(); void Print(); unsigned int GetAge(){//不允许调用 父类 的私有成员 return age; //如果我们想调用的话,可以把 age 声明成 protected 成员 } }; CWorker::CWorker(char szName[], unsigned int uiAge, char szCompany[]) :CPerson(szName, uiAge){ //CPerson::CPerson(szName, uiAge); //不能这样写,因为这样写相当于定义一个新 CPerson 对象 //在外部调用父类构造函数构造对象, //如果在函数里面 调用, 则会生成一个新的 CPerson 对象 (匿名对象) strcpy(company,szCompany); } CWorker::~CWorker(){} void CWorker::Carry(){ cout << "Carry something ..." << endl; }; void CWorker::Print(){ CPerson::Print(); //指定调用父类的Print函数, //不加CPerson:: 则会有限调用自己定义的 Print() --> 无限递归 cout << "公司 :" << company << endl; } class CFarmer:public CPerson { private: char address[20]; //农民的土地位置 public: CFarmer(char szName[], unsigned int uiAge, char szAddr[]); ~CFarmer(){} void Sow(); void Print(); }; CFarmer::CFarmer(char szName[], unsigned int uiAge, char szAddr[]) :CPerson(szName, uiAge){ strcpy(address,szAddr); } void CFarmer:: Print(){ CPerson::Print(); cout << "土地 :" << address << endl; } void CFarmer::Sow(){ cout << "Sow seed ..." << endl; }; class CMigrantWorker :public CWorker, public CFarmer { private: char cardStr[20]; //暂住证卡号 public: CMigrantWorker(char szName[], unsigned int uiAge, char szAddr[], char szCompany[], char szCard[]); ~CMigrantWorker(); void Print(); }; CMigrantWorker::CMigrantWorker(char szName[], unsigned int uiAge, char szAddr[], char szCompany[], char szCard[]) :CWorker(szName, uiAge, szCompany), CFarmer(szName, uiAge, szAddr){ strcpy(cardStr,szCard); } CMigrantWorker::~CMigrantWorker(){} void CMigrantWorker::Print(){ CWorker::Print(); CFarmer::Print(); cout << "暂住证:" << cardStr << endl; } void TestInherit() { CWorker W1("小王", 30, "腾信"); W1.Print(); //事实上就调用了父类的 Print() //并不是说父类CPerson 的所有函数,CWorker 都能调用 //CWorker 不能调用 CPerson 的 private 中的变量和函数 //W1.age = 40;// 不允许调用父类的私有成员 //protected:受保护的成员,子类中的函数,可以直接调用。 //如果子类也定义了 Print() 函数(同名,而且入参一样),那么,会隐藏掉父类的函数。 CMigrantWorker M1("张铁柱", 40, "空空搬家", "麦田1号", "zzz20170322"); M1.Print(); M1.Sow(); M1.Carry(); } int main() { TestInherit(); //system("pause"); return 0; }
//C++学习笔记_04抽象类、多态 (继承\抽象类\多态) #include <cstdio> #include <cstring> #include<iostream> using namespace std; class CAnimal { protected: char name[16]; public: CAnimal(char szName[]) {strcpy(name,szName);} void eat() {cout << "Animal " << name << " 吃东西 ..." << endl;} virtual void play() {cout << "Animal " << name << " 瞎玩..." << endl;} virtual void run()=0;//直接用0给函数赋值 run()函数就 成了纯虚函数 //也是用于实现多态,不过纯虚函数要求子类必须实现这个函数 //一个类中,只要存在纯虚函数,那么这个类我们称之为抽象类 //抽象类不能生成对象 /* {cout << "Animal " << name << " 瞎跑..." << endl;}*/ ~CAnimal(){} }; //CMonkey 继承了 CAnimal //那么 CAnimal内的所有成员,在 CMonkey里面都包含了 //既然包含的话,需要初始化(使用构造函数初始化) class CMonkey :public CAnimal { private: public: //构造子类的之前,会先构造父类(不写则默认调用父类的默认构造函数) //父类没有默认构造函数,显式指定构造方式为 CAnimal(szName) CMonkey(char szName[]) :CAnimal(szName) {} ~CMonkey() {}; void eat() {cout << "Monkey " << name << " 吃香蕉 ..." << endl;} void play() {cout << "Monkey " << name << " 翻跟头... " << endl;} void run() {cout << "Monkey " << name << " 手脚并用的跑..." << endl;} }; class CBird :public CAnimal { public: CBird(char szName[]) :CAnimal(szName){} ~CBird(){} void eat() {cout << "Bird " << name << " 吃虫子 ..." << endl;} void play() {cout << "Bird " << name << " 唱歌... " << endl;} void run() {cout << "Bird " << name << " 飞翔..." << endl;} }; void TestAnimal() { //动物园开春晚。各种动物报名。 //我们要使用一个数组来保存各个动物 CMonkey M1("小猴子"); CMonkey M2("老猴子"); CBird B1("叽叽"); CBird B2("喳喳"); CAnimal *pAni[4]; //指针数组:数组里面的元素都是指针 //定义父类的指针,指向子类的对象 pAni[0] = &M1; pAni[1] = &M2; pAni[2] = &B1; pAni[3] = &B2; for (int i = 0; i < 4; i++){ //一旦把他们综合到一起了,他们就失去了自己独有的特性 //都会调用父类的函数 pAni[i]->eat(); } cout<<endl; for (int i = 0; i < 4; i++){ //现在我们把 父类 的成员函数 play 前面加一个 virtual 来修饰 //表示play 是一个虚函数 //在调用的时候,优先调用子类的函数 pAni[i]->play(); //通过指针数组来 调用 方法: //会根据 指向对象的不同,来调用 不同的 方法 //---不同的对象,打开姿势不一样 ---》多态 } cout<<endl; CAnimal &Ani = M1; //Ani 是 CAnimal 变量 //如果说,它是一个别名的话, Ani 和 M1 应该是完全一样的 //但是我们调用函数来看看 Ani.eat(); M1.eat(); //他们调用同一个方法,动作是不一样的,所以不能说两个是一样的,并不是取一个别名 //应该说,引用定义了一个隐含指针ptr,指向 M1, 我们使用 Ani 的时候,就相当于使用 *ptr cout<<endl; //我们不能使用对象来做 //CAnimal arrAni[4] = { M1, M2, B1, B2 };//抽象类不能生成对象 //这里事实上,调用的是 复制构造函数(只复制数据) arrAni[i] 就是 CAnimal对象 for (int i = 0; i < 4; i++) { //把 run 定义成虚函数后 //如果子类没有实现 (CBird) --> 会调用父类的函数 //我们有可能漏了这个东西? //动物跑动,这个方法不叫笼统,我们需要各个具体动物自己定义跑动 //比如猴子-跑,虫子-爬,乌-飞.. //强制子类必须定义run()方法-->使用纯虚函数 pAni[i]->run(); } } int main() { TestAnimal(); //system("pause"); return 0; }