通过哺乳类派生猫、狗等学习继承、多态中的知识点
先贴上类的代码
#include<iostream>
enum BREED { YORKIE, CAIRN, DANDIE, SHETLAND, DOBERAMN, LAB };//犬种
class Mammal {
public:
Mammal() :age(2), weight(5) {}
//~Mammal() { std::cout << "Mamal 销毁" << std::endl; }//析构函数
//如果基类Mammal没有声明虚析构函数,释放派生类时将不能调用派生类的析构函数
virtual~Mammal() { std::cout << "Mamal 销毁" << std::endl; }//虚析构函数
//虚复制构造函数
//通过基类指针创建一个派生类对象的拷贝
virtual Mammal* clone() { return new Mammal(*this); }
int getAge()const { return age; }
void setAge(int newAge) { age = newAge; }
int getWeight()const { return weight; }
void setWeight(int newWeight) { weight = newWeight; }
//void speak() { std::cout << "Mamal Sound!" << std::endl; }
virtual void speak()const { std::cout << "Mamal Sound!" << std::endl; }//虚函数
void move()const { std::cout << "Mamal moving..." << std::endl; }
void sleep() { std::cout << "Mamal Sleeping!" << std::endl; }
protected:
int age;
int weight;
};
class Dog :public Mammal {
public:
Dog() :itsBreed(YORKIE) {}
~Dog() { std::cout << "Dog 销毁" << std::endl; }
//虚复制构造函数
//通过基类指针创建一个派生类对象的拷贝
virtual Mammal* clone() { return new Dog(*this); }
BREED getBreed()const { return itsBreed; }
void setBreed(BREED newBreed) { itsBreed = newBreed; }
void speak()const { std::cout << "Woof!..." << std::endl; }
void move()const { std::cout << "Dog moving..." << std::endl; }
void wagTail() { std::cout << "Tail wagging..." << std::endl; }
void begForFood() { std::cout << "Begging for food..." << std::endl; }
protected:
BREED itsBreed;
};
//以下是简化类
class Cat :public Mammal {
public:
~Cat() { std::cout << "Cat 销毁" << std::endl; }
//虚复制构造函数
//通过基类指针创建一个派生类对象的拷贝
virtual Mammal* clone() { return new Cat(*this); }
void speak()const { std::cout << "Meow!..." << std::endl; }
void purr()const { std::cout << "Rrrrrrrrrrrrr..." << std::endl; }//Cat特有的方法
};
class Horse :public Mammal {
public:
~Horse() { std::cout << "Horse 销毁" << std::endl; }
//如果没有定义虚复制构造函数,将调用基类Mammal的方法,因为派生的Horse部分没有复制过来
virtual Mammal* clone() { return new Horse(*this); }
void speak()const { std::cout << "Whinny!..." << std::endl; }
};
class Pig :public Mammal {
public:
~Pig() { std::cout << "Pig 销毁" << std::endl; }
virtual Mammal* clone() { return new Pig(*this); }
void speak()const { std::cout << "Oink!..." << std::endl; }
};
主程序
#include <iostream>
#include <string>
#include "mammal.h"
//调用speak方法
void valuefuction(Mammal mammalvalue);//切除,speak调用Mammal版本
void ptrfuction(Mammal *mammalvalue);
void reffuction(Mammal &mammalvalue);
int main()
{
Mammal *pDog = new Dog;
pDog->speak();//pDog是Mammal对象,但是speak是虚成员函数,调用Dog中的方法
pDog->move();//pDog是Mammal对象,调用Mammal中的方法//dog没有此方法
std::cout << "+++++++++++++++++++++++++Mammal指针数组+++++++++++++++++++++++++" << std::endl;
Mammal *array[5] = { new Dog,new Cat,new Horse,new Pig,new Mammal };
for (int i = 0; i < 5; i++) {
//array[i]->speak();
(*array[i]).speak();//先解析再调用方法,与上一句同义
delete[]array[i]; //释放指针数组需迭代?
}
//delete[]array;//错误,释放指针数组需迭代?
std::cout << "+++++++++++++++++++++++++Mammal切除+++++++++++++++++++++++++" << std::endl;
//调用speak方法
Mammal *ptr = new Dog;
valuefuction(*ptr);//切除,speak调用Mammal版本,因为参数为Mammal对象
ptrfuction(ptr);
reffuction(*ptr);
ptr = new Cat;
valuefuction(*ptr);//切除,speak调用Mammal版本,因为参数为Mammal对象
ptrfuction(ptr);
reffuction(*ptr);
std::cout << "++++++验证虚析构函数++++++++++" << std::endl;
Mammal *Animal = new Mammal;
Dog *pDog55 = new Dog;
Mammal *horse = new Horse;
delete horse;//如果基类Mammal没有声明虚析构函数,将不能调用Horse的析构函数
//可以通过注释Horse类中的虚析构函数验证
delete Animal;
delete pDog55;
std::cout << "++++++验证虚析构函数+++++++++++++" << std::endl;
std::cout << "++++++验证虚复制构造函数+++++++++++++" << std::endl;
Mammal *dog1 = new Dog;
Mammal *horse1 = new Horse;
dog1->speak();
horse1->speak();
Mammal *dog2 = dog1->clone();
Mammal *horse2 = (*horse1).clone();
dog2->speak();//Dog类定义了虚复制构造函数,可以正确调用Dog类的speak方法
horse2->speak();//Horse类如果没有定义虚复制构造函数,将调用基类Mammal的方法,因为派生的Horse部分没有复制过来
//注释虚复制函数得到不同结果
std::cout << "++++++验证虚复制构造函数+++++++++++++" << std::endl;
std::cout << "++++++验证dynamic_cast转换 通过基类指针访问派生类特定函数+++++++++++" << std::endl;
Mammal *cat1 = new Cat;
cat1->speak();
Cat* pcat = dynamic_cast<Cat*>(cat1);
//cat1->purr();//错误,应该使用转换得到的新指针调用
pcat->purr();
return 0;
}
void valuefuction(Mammal mammalvalue)
{
mammalvalue.speak();
}
void ptrfuction(Mammal * mammalvalue)
{
mammalvalue->speak();
}
void reffuction(Mammal & mammalvalue)
{
mammalvalue.speak();
}
笔记:
虚复制构造函数
通过基类指针创建一个派生类对象的拷贝
基类指针指向派生类对象,怎样用基类指针创建一个新的派生类对象?
虚析构函数:当且仅当类里包含至少一个虚函数的时候才去声明虚析构函数。
如果释放派生类时,基类没有声明虚析构函数,将不能调用派生类的析构函数
基类指针不能访问派生类特有的成员函数,可用dynamic_cast转换符运算符把基类指针转换为派生类指针,如果转换失败指针为空
抽象类与具体类比较
1.抽象类不能直接实例化
2.抽象类可以不含抽象方法
3.抽象类中含有抽象方法时,如果子类继承该抽象类,则必须重写该抽象方法
4.抽象类可以有非抽象方法
5.允许(但不要求)抽象类包含抽象成员。
6.抽象类不能被密封。
7.抽象类含有非抽象方法,而且子类继承该类时,重写了该方法,那么该子类的对象调用该方法时,是子类中的方法;如果子类没有重写该父类中的非抽象方法,那么子类对象调用的是父类中的方法。