1、多态是指同一行为不同对象会产生不同结果。
2、多态形成的条件:
(1)虚函数的重写(重写该函数的实现)
(2)父类指针或者引用调用该函数
a、虚函数:
被virtual修饰的函数,父类函数前必须写,派生类不做要求,但建议写上。
注:virtual无法修饰静态函数
虚函数重写要做到三同:
函数名参数与返回类型相同
但有两个例外:
协变(基类与派生类的返回类型不同)
析构函数的重写(虽然其函数名不同,但其会被编译器统一处理为destructor的函数名称)
//class Person {
//public:
// virtual ~Person()
// {
// cout << "~Person()" << endl;
// }
//
//};
//
//class Student : public Person {
//public:
// ~Student() override
// {
// delete _ptr;
// cout << "~Student():"<< _ptr<< endl;
// }
//protected:
// int* _ptr = new int[10];
//};
//
//int main()
//{
// //Student st;
//
// Person* p1 = new Student;
//
// // 实现多态,就正常了
// //
// // p1->destructor() + operator delete(p1)
// delete p1;
//
// Person* p2 = new Person;
// delete p2;
//
//
//
// return 0;
//}
3、
4、
5、虚(函数)表(本质上为虚函数指针数组)
类中的虚函数均存在于指针数组中方便访问
形似:
注意打印地址时,成员函数需加取地址符号并指明类域
class Base
{
public:
virtual void Func1()
{
cout << "Base::Func1()" << endl;
}
virtual void Func2()
{
cout << "Base::Func2()" << endl;
}
void Func3()
{
cout << "Base::Func3()" << endl;
}
private:
int _b = 1;
};
class Derive : public Base
{
public:
virtual void Func1()
{
cout << "Derive::Func1()" << endl;
}
private:
int _d = 2;
};
void Func1(Base* p)
{
// 运行时绑定/动态绑定
p->Func1();
// 编译时绑定/静态绑定
p->Func3();
}
//int main()
//{
// Base b;
// Derive d;
//
// Func1(&b);
// Func1(&d);
//
// return 0;
//}
//int main()
//{
// const char* str = "11111111";
// cout << str << endl;
//
// Base b;
//
// printf("%p\n", str);
// printf("%p\n", &Base::Func1);
// printf("%p\n", &Base::Func2);
// printf("%p\n", &Base::Func3);
//
// int a = 0;
// printf("%p\n", &a);
//
// return 0;
//}
总结:
6、动态绑定与静态绑定
动:虚函数在多态中的调用,又称运行时绑定
jing:普通函数的选择,又称编译时绑定
7、虚表在常量区
//int main()
//{
// int i = 0;
// static int j = 1;
// int* p1 = new int;
// const char* p2 = "xxxxxxxx";
// printf("栈:%p\n", &i);
// printf("静态区:%p\n", &j);
// printf("堆:%p\n", p1);
// printf("常量区:%p\n", p2);
//
// Base b;
// Derive d;
//
// // int/double/char
// // int和int* 指针之间
// printf("Base虚表地址:%p\n", *((int*)&b));
// printf("Derive虚表地址:%p\n", *((int*)&d));
// printf("Base对象地址:%p\n", &b);
// printf("Derive对象地址:%p\n", &d);
//
// Base b1;
// Base b2;
// Base b3;
//
// return 0;
//}