#include
using namespace std;
class Hero
{
public:
//1 多态的必要条件1:要有virtual修饰的虚函数
virtual int getAd()
{
cout << "SuperHero getAd ---> 10" << endl;
return 10;
}
};
class SuperHero : public Hero
{
public:
//2 多态的必要条件2:继承父类并重写虚函数
int getAd()
{
cout << "SuperHero getAd ---> 100" << endl;
return 100;
}
};
//3 多态的必要条件3:父类的指针指向子类对象
void fight(Hero *hero)
{
hero->getAd();
}
int main(void){
Hero hero;
SuperHero superHero;
fight(&hero);
fight(&superHero);
return 0;
}
执行结果
SuperHero getAd ---> 10
SuperHero getAd ---> 100
如果父类方法不用virtual关键字修饰
int getAd()
{
cout << "SuperHero getAd ---> 10" << endl;
return 10;
}
执行结果
SuperHero getAd ---> 10
SuperHero getAd ---> 10
#include
using namespace std;
class TestA
{
public:
TestA(){
cout << "TestA()" << endl;
this->p = new char[64];
memset(p, 0, 64);
strcpy(p, "string in TestA");
}
virtual void print()
{
cout << " TestA print() ---> p = " << p << endl;
}
~TestA()
{
cout << "~TestA()" << endl;
if(p != NULL)
{
delete [] p;
p = NULL;
}
}
private:
char *p;
};
class TestB : public TestA
{
public:
TestB(){
cout << "TestB()" << endl;
this->p = new char[64];
memset(p, 0, 64);
strcpy(p, "string in B");
}
void print()
{
cout << " TestB print() ---> p = " << p << endl;
}
//1 不加virtual关键字,当父类指向子类的对象析构时,将不会执行子类的析构函数
~TestB()
{
cout << "~TestB()" << endl;
if(p != NULL)
{
delete [] p;
p = NULL;
}
}
private:
char *p;
};
void myDelete(TestA* p)
{
delete p;
}
void test1()
{
TestB *b = new TestB;
b->print();
myDelete(b);
}
int main(void){
test1();
return 0;
}
析构函数不加 virtual关键字,执行结果
TestA()
TestB()
TestB print() ---> p = string in B
~TestA()
加virtual关键字后,执行结果
TestA()
TestB()
TestB print() ---> p = string in B
~TestB()
~TestA()
(1) 虚函数的解释
1 当类中声明虚函数时,编译器会在类中生成一个虚函数表;
2 虚函数表示一个存储类成员值函数指针的数据结构,由编译器自动生成和维护
3 virtual成员函数会被编译器放入虚函数表中
4 存在虚函数时,每个对象中都有一个指向虚函数表的指针(vptr)
(2) 编译器确定func是否为虚函数
1 func不是虚函数: 编译器可直接确定被调用的成员函数(静态联编)
2 func是虚函数: 编译器根据对象的vptr指针,在所指向的虚函数表中查找func()函数并调用。(查找好调用在运行是完成,即动态联编)
(3) 执行效率对比
1 通过虚函数表指针vptr调用重写函数是在程序运行时进行的,因此需要通过寻址操作才能确定真正应该调用的函数,
而普通函数在编译时就确定了调用的函数,在效率上,虚函数的效率要低很多,出于效率考虑,没有必要将素有函数都声明为虚函数
#include
using namespace std;
class Parent1
{
public:
virtual void func(int a, int b)
{
}
private:
int a;
};
class Parent2
{
public:
void func(int a, int b)
{
}
private:
int a;
};
int main(void){
Parent1 p1;
Parent2 p2;
cout << " sizeof(p1) = " << sizeof(p1) << endl;
cout << " sizeof(p2) = " << sizeof(p2) << endl;
return 0;
}
执行结果
sizeof(p1) = 16
sizeof(p2) = 4
p2占用4个字节,是因为int类型占用4字节。
而p1占用int类型 + 指针类型 = 4 + 8 = 12字节。而结果是16,是因为这里有个字节对齐,需要偏移4字节。
具体可参考
#pragma pack()
可参考以下内容
#include
using namespace std;
#pragma pack(1)
class Parent1
{
public:
virtual void func(int a, int b)
{
}
private:
int a;
};
class Parent2
{
public:
void func(int a, int b)
{
}
private:
int a;
};
#pragma pack()
int main(void){
Parent1 p1;
Parent2 p2;
cout << " sizeof(p1) = " << sizeof(p1) << endl;
cout << " sizeof(p2) = " << sizeof(p2) << endl;
cout << " sizeof(int*) = " << sizeof(int*) << endl;
return 0;
}
此时的执行结果
sizeof(p1) = 12
sizeof(p2) = 4
sizeof(int*) = 8
1 对象在创建时,由编译器对vptr指针进行初始化
2 只有在对象的构造完全结束后,vptr的指向才最终确定
3 父类对象的vptr指向父类虚函数表
4 子类对象的vptr指向子类虚函数表
#include
using namespace std;
class Parent
{
public:
Parent(int a):a(a)
{
cout << "Parent(int a)" << endl;
//1 虽然print()方式虚函数,但是此时vptr还没有初始化,所以调用的是父类的方法
print();
}
virtual void print()
{
cout << "Parent print() a= " << a << endl;
}
private:
int a;
};
class Child : public Parent
{
public:
Child(int a, int b) : Parent(a),b(b)
{
cout << "Child(int a, int b)" << endl;
print();
}
void print()
{
cout << "Child::print() b = " << b << endl;
}
private:
int b;
};
int main(void){
Parent *p = new Child(10, 20);
p->print();
delete p;
return 0;
}
执行结果
Parent(int a)
Parent print() a= 10
Child(int a, int b)
Child::print() b = 20
Child::print() b = 20
#include
using namespace std;
class Parent
{
public:
Parent(int a)
{
this->a = a;
}
virtual void print()
{
cout << "Parent print() a = " << a << endl;
}
protected:
int a;
};
class Child : public Parent
{
public:
Child(int a) : Parent(a)
{
}
virtual void print()
{
cout << "Child print() a = " << a << endl;
}
int b;
};
int main(void){
Child array[] = {Child(0), Child(1), Child(2)};
Child *cp = &array[0];
Parent *pp = &array[0];
cp->print();
pp->print();
cp++;
cp->print();
//1 因为父类和子类的步长相等,所以父类的++操作也可以从数组中取值
pp++;
pp->print();
return 0;
}
执行结果
Child print() a = 0
Child print() a = 0
Child print() a = 1
Child print() a = 1
1 含有纯虚函数的类,称为抽象基类,不可实例化,即不能创建实例对象。存在的意义就是被继承,提供族类的公共接口。
2 纯虚函数只有声明,没有实现。都是以virtual void func() = 0;的形式
3 如果一个勒种声明了纯虚函数,而在派生类中没有对该函数的定义,则该虚函数在派生类中仍然为纯虚函数,派生类仍然为出纯虚基类
纯虚函数的语法示例
virtual void func() = 0;
有纯虚函数的类即为抽象类
#include
using namespace std;
class Shape
{
public:
//1 纯虚函数 子类必须实现
virtual double getCircleArea() = 0;
virtual void print() = 0;
};
class Circle : public Shape
{
public:
Circle(double r)
{
this->r = r;
}
//必须要实现抽象方法
double getCircleArea()
{
return 3.14 * r * r;
}
//必须要实现抽象方法
void print()
{
cout << "圆的面积是: " << this->getCircleArea() << endl;
}
private:
double r;
};
int main(void){
Shape *sp = new Circle(10.0);
sp -> print();
return 0;
}
执行结果
圆的面积是: 314
1 C++中没有类似Java中的接口类,可以用纯虚函数来实现接口类
2 接口类中只有函数原型的定义,不做具体实现
class Interface
{
public:
virtual void func1() = 0;
virtual void func2() = 0;
}
#include
using namespace std;
class BasketBallPlayer
{
public:
virtual void play() = 0;
};
class James : public BasketBallPlayer
{
public:
void play()
{
cout << "James 打篮球" << endl;
}
};
int main(void){
BasketBallPlayer *player = new James;
player->play();
delete player;
return 0;
}
执行结果
James 打篮球
#ifndef Animal_hpp
#define Animal_hpp
#include
using namespace std;
class Animal
{
public:
Animal();
virtual ~Animal();
virtual void voice() = 0;
};
void AnimalVoice(Animal *ap);
#endif /* Animal_hpp */
#include "Animal.hpp"
Animal::Animal()
{
cout << "Animal()" << endl;
}
Animal::~Animal()
{
cout << "~Animal()" << endl;
}
void AnimalVoice(Animal *ap)
{
cout << "动物开始叫了" << endl;
ap->voice();
cout << "动物叫完了" << endl;
}
#ifndef Cat_hpp
#define Cat_hpp
#include "Animal.hpp"
class Cat:public Animal
{
public:
Cat();
~Cat();
virtual void voice();
};
#endif /* Cat_hpp */
#include "Cat.hpp"
Cat::Cat()
{
cout << "Cat()..." << endl;
}
Cat::~Cat()
{
cout << "~Cat()..." << endl;
}
void Cat::voice()
{
cout << "喵喵猫" << endl;
}
#ifndef Dog_hpp
#define Dog_hpp
#include "Animal.hpp"
class Dog : public Animal
{
public:
Dog();
~Dog();
virtual void voice();
};
#endif /* Dog_hpp */
#include "Dog.hpp"
Dog::Dog()
{
cout << "Dog()" << endl;
}
Dog::~Dog()
{
cout << "~Dog()" << endl;
}
void Dog::voice()
{
cout << "汪汪汪" << endl;
}
#include "Animal.hpp"
#include "Dog.hpp"
#include "Cat.hpp"
int main(void)
{
Animal *ap = new Dog;
//1 调用全局函数
AnimalVoice(ap);
delete ap;
cout << "=================" << endl;
ap = new Cat;
AnimalVoice(ap);
delete ap;
return 0;
}
执行结果
Animal()
Dog()
动物开始叫了
汪汪汪
动物叫完了
~Dog()
~Animal()
=================
Animal()
Cat()...
动物开始叫了
喵喵猫
动物叫完了
~Cat()...
~Animal()