目录
[重载 重定义 重写](#重载 重定义 重写)
多态的概念
多态:一种接口,多种形态
静态多态:如果函数的调用,在编译阶段就可以确定函数的调用地址,并产生代码,就是静态多态(编译时多态)
动态多态:调用地址不能编译不能在编译期间确定,而需要在运行时才能决定,这这就属于晚绑定(动态多态,运行时多态)
发生多态的四个条件:
父类中有虚函数
必须发生继承
子类必须重写虚函数(函数名 参数 返回值一致 函数的内容可以不一致)
父类的指针或引用指向子类的对象
cpp
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
class Dog:virtual public Animal
{
public:
//重写虚函数 函数的返回值 参数 函数名一样
void speak()
{
cout << "狗在说话" << endl;
}
};
class Cat:virtual public Animal
{
public:
//重写虚函数 函数的返回值 参数 函数名一样
void speak()
{
cout << "猫在说话" << endl;
}
};
//如果两个类发生了继承 父类和子类编译器都会自动转换 不需要人为转换
void do_work(Animal &obj)//多态接口 一个函数实现不同功能
{
obj.speak();//地址早绑定->加上函数前面加上virtual 地址晚绑定
}
void test01()
{
Animal p1;
do_work(p1);//动物
Dog p2;
do_work(p2);//狗
Cat p3;
do_work(p3);//猫
}
int main()
{
test01();
return 0;
}
多态实现计算器案例
cpp
#include <iostream>
using namespace std;
class Calc
{
public:
virtual int mycalc(int a,int b)
{
return 0;
}
};
class Add:public Calc
{
public:
int mycalc(int a,int b)
{
return a + b;
}
};
class Mul:public Calc
{
public:
int mycalc(int a,int b)
{
return a * b;
}
};
class Sub:public Calc
{
public:
int mycalc(int a,int b)
{
return a - b;
}
};
int do_calc(int a,int b,Calc &obj)
{
return obj.mycalc(a,b);
}
void test01()
{
Add p1;
cout << do_calc(3,4,p1) << endl;
Mul p2;
cout << do_calc(3,4,p2) << endl;
Sub p3;
cout << do_calc(3,4,p3) << endl;
}
int main()
{
test01();
return 0;
}
c++如何实现动态绑定
为什么可以根据传入对象的不同来执行不同的语句?
纯虚函数和抽象类
纯虚函数:将虚函数等于0 实质是将虚函数 表的函数入口设为NULL
抽象类:一个类如果有纯虚函数,那么这个类就是一个抽象类,抽象类不能实例化对象
继承抽象类的子类也是一个抽象类,如果子类重写了虚函数,那么子类就不是抽象类
cpp
class Calc
{
public:
virtual int mycalc(int a,int b) = 0;//虚函数等于0 纯虚函数
};
class Mob:public Calc
{
public:
//子类继承了抽象类 子类也是抽象类
//如果子类重写虚函数 就不是抽象类
};
//如果有纯虚函数的类 叫做抽象类 抽象类无法实例化对象
void test()
{
//Cacl p;//错误
Mod p1;
}
纯虚函数和多继承
多继承带来了一些争议,但是接口继承可以说一种毫无争议的运用了。
绝大数面向对象语言都不支持多继承,但是绝大数面向对象对象语言都支持接口的概念, c++ 中没有接口的概念, 但是可以通过纯虚函数实现接口。
接口类中只有函数原型定义,没有任何数据定义。
多重继承接口不会带来二义性和复杂性问题。接口类只是一个功能声明,并不是功能实现,子类需要根据功能说 明定义功能实现。
注意 : 除了析构函数外,其他声明都是纯虚函数。
虚析构函数
虚析构函数作用
在调用基类的析构函数之前,先调用子类的析构函数
cpp
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
virtual ~Animal()
{
cout << "动物的析构" << endl;
}
};
class Dog:virtual public Animal
{
public:
//重写虚函数 函数的返回值 参数 函数名一样
void speak()
{
cout << "狗在说话" << endl;
}
~Dog()
{
cout << "狗的析构" << endl;
}
};
class Cat:virtual public Animal
{
public:
//重写虚函数 函数的返回值 参数 函数名一样
void speak()
{
cout << "猫在说话" << endl;
}
};
//如果两个类发生了继承 父类和子类编译器都会自动转换 不需要人为转换
void do_work(Animal &obj)//多态接口 一个函数实现不同功能
{
obj.speak();//地址早绑定->加上函数前面加上virtual 地址晚绑定
}
void test01()
{
Animal *p = new Dog;
p->speak();//调用狗的speak
delete p;//加virtual 调用动物的析构 加virtual之后先调用狗的析构 再调用动物的析构
}
int main()
{
test01();
return 0;
}
纯虚析构函数
虚构函数等于零
class Animal
{
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
virtual ~Animal() = 0;//
};
重载 重定义 重写
重载:
函数名相同
同一个作用域
参数的个数、顺序、类型不一致
const也可以成为重载的条件
重定义:
发生继承
子类和父类有同名的变量和函数,父类中同名的变量和函数会被隐藏
重写:
父类中有虚函数
发生了继承
子类重写了虚函数
函数名、返回值、参数一致,函数体不一致