C++多态

Day07总结

静态联编和动态联编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
 * 静态联编和动态联编
* 静态多态——函数重载、运算符重载
* 动态多态——父子间继承+虚函数
* 动态多态满足条件
* 1.父类中有虚函数
* 2.子类重写父类的虚函数
* 3. 父类的指针或者引用指向子类的对象
void doSpeak(Animal & animal)
* 重写的意义
* 子类重新实现父类中的虚函数,必须返回值,函数名,参数一致才称为重写
* 在子类中,重写函数前 virtual可加可不加
class Animal
{
public:
//加上virtual以后,变成了虚函数
virtual void speak()
{
cout<<"ANIMAL IS TALKING"<<endl;
}
virtual void eat()
{
cout<<"ANIMAL IS EATING"<<endl;
}
};

class Cat:public Animal
{
public:
void speak()
{
cout<<"THE CAT IS SPEAKING!!"<<endl;
}
void eat()
{
cout<<"THE CAT IS EATING!!"<<endl;
}
};

class Dog:public Animal
{
public:
void speak()
{
cout<<"THE DOG IS SPEAKING!!"<<endl;
}
void eat()
{
cout<<"THE DOG IS EATING!!"<<endl;
}
};
void doSpeak(Animal & animal)
//Animal & animal = cat 父类的指针或者引用指向子类的对象
{
animal.speak();
}
void doeat(Animal & animal)
//Animal & animal = cat 父类的指针或者引用指向子类的对象
{
animal.eat();
}
//引用指向
void test01()
{
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
}
//指针指向
void test02()
{
Animal *animal = new Cat;
Animal*animal1 =new Dog;
}

02多态原理

03多态案例——计算器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
* 多态案例——计算器
* 1. 多态的好处:对拓展性的提高,组织性强,可读性强
* 2. 如果父类中有了虚函数,子类并没有重写父类的虚函数,那么这样的代码毫无意义
* 3. 如果子类不重写父类的虚函数,那么没有用到多态带来的好处 ,反而内部结构变化,复杂
class AbstractCal
{
public:
//纯虚函数
virtual int getResult() = 0;//运行效果和原来一样
//但是,如果一个类中有纯虚函数出现,这个类就无法实例化对象了
//有纯虚函数的类,称为抽象类、
//如果抽象类中有纯虚函数,子类中必须重写纯虚函数!!!否则子类也属于抽象类!!!也无法创造子类对象
virtual int getResult()
{
return 0;
}
int m_A;
int m_B;
};
//加法计算器
class AddCalculator:public AbstractCal
{
public:
virtual int getResult()
{
return m_A+m_B;
}
};
//减法计算器
class SubCalculator:public AbstractCal
{
public:
virtual int getResult()
{
return m_A-m_B;
}
};
//如果再加乘法,直接写子类
class MultiCalculator:public AbstractCal
{
public:
virtual int getResult()
{
return m_A*m_B;
}
};
//除法
class ChuCalculator:public AbstractCal
{
public:
virtual int getResult()
{
return m_A/m_B;
}
};
void test01()
{
AbstractCal *calculator = new AddCalculator;
calculator->m_A = 100;
calculator->m_B= 10;
cout<<calculator->getResult()<<endl;
calculator = new SubCalculator;//让calculator重新指向减法
calculator->m_A = 100;
calculator->m_B= 10;
cout<<calculator->getResult()<<endl;
}

04抽象类和纯虚函数

纯虚函数语法

  • virtual void func() =0;
  • 如果类中有了纯虚函数,那么这个类也称为抽象类
  • 抽象类 是无法实例化对象的
  • 如果抽象类中有纯虚函数,子类中必须重写纯虚函数!!!否则子类也属于抽象类!!!也无法创造子类对象
  • 子类必须实现所有的纯虚函数!
  • virtual void func() =0;告诉编译器在vtable中为函数保留一个位置,但这个位置不放入地址

05虚析构和纯虚析构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
*      如果子类中有属性创建在堆区,那么多态情况下,不会调用子类的析构代码,导致内存泄漏
* 解决方案:虚析构或者纯虚析构
* 虚析构:在析构前加关键词virtual即可
* 纯虚析构 virtual ~函数名()=0
* 纯虚析构::类内声明,类外实现
* 如果一个类中有了纯虚析构函数后,那么这个类也属于抽象类型,不能实例化了
* 但是有虚析构,不属于抽象类型,任然能实例化
class Animal
{
public:
Animal()
{
cout<<"ANIMAL 的构造函数调用"<<endl;
}
// 虚析构
virtual ~Animal()//有了虚析构,解决了
{
cout<<"Animal 虚析构函数的调用"<<endl;
}
// 纯虚析构,类内实现
virtual ~Animal() = 0;
};
//类外声明
Animal::~Animal()
{
cout<<"Animal 纯虚析构函数的调用"<<endl;
}

06向上向下类型转换

07重写重载重定义

-------------本文结束,感谢您的阅读-------------