一、写在多态之前
class Animal {
public:
void shout() {
cout << "Shout" << endl;
}
};
class Cat : public Animal {
public:
void shout() {
cout << "Meow" << endl;
}
};
void main(){
Animal a;
Cat c;
Animal ap=c;
ap.shout();//Shout,not Meow
}
父类对象可以=子类对象,子类对象不可以=父类对象(后者调用构造函数时会空了一部分)。(重点)
二、多态
1、多态的定义
多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
函数重载属于静态多态
。
class Dog : public Animal {
public:
void shout() {
cout << "Woof" << endl;
}
};
void test(Animal* a) {
a->shout();
}
void test(Animal& a) {
a.shout();
}
void main() {
Cat c;
Dog d;
test(&c);//test(c);
//Shout,not Meow
test(&d);//test(d);
//Shout,not Woof
}
这里的原理跟最开始那个例子的原理一样。这里并不能实现多态,下面引入虚函数。
2、虚函数(与虚基类无任何关系)(重点)
虚函数是在父类中使用关键字virtual
声明的函数。在子类中重新定义父类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
class Animal {
public:
virtual void shout() {
cout << "Shout" << endl;
}
};
void test(Animal* a) {
a->shout();
}
void test(Animal& a) {
a.shout();
}
在前面加个virtual
关键字就能实现多态了。
注意形参类型只能是父类的指针或引用。
test(&c);//test(c);
//Meow,not Shout
test(&d);//test(d);
//Woof,not Shout
再来看此时一个Animal
对象的大小
void main() {
Animal a;
cout << sizeof(a) << endl;//输出4
}
//虚函数指针指向虚函数表(函数地址保存在这个表里)
3、纯虚函数
父类中不能对虚函数给出有意义的实现时会用到纯虚函数。
class Animal {
public:
virtual void shout() = 0;
};
拥有纯虚函数的类叫做抽象类。
4、虚析构函数
class Animal {
public:
Animal() {
cout << "Animal()" << endl;
}
~Animal() {
cout << "~Animal()" << endl;
}
virtual void shout() = 0;
};
class Cat : public Animal {
public:
int* age;
Cat() : age(new int(18)) {
cout << "Cat()" << endl;
}
~Cat() {
delete age;
cout << "~Cat()" << endl;
}
void shout() {
cout << "Meow: " << *age << endl;
}
};
void test() {
Animal* a = new Cat();
a->shout();
delete a;//这里不会调用~Cat()函数,出现了内存泄露,导致Cat类没有删干净
}
要想调用~cat()函数,改成下面的代码即可:
virtual ~Animal() {
cout << "~Animal()" << endl;
}