CentOS 7 搭建 DNS 主从服务
2026/7/13 6:17:50
本文中的代码都是在X64环境下编译运行的,涉及的指针都是8bytes,切换其他平台需要考虑指针问题。
多态的构成条件:
多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象买票全价,Student对象买票半价。
那么在继承中要构成多态还有两个条件:
a. . 必须通过基类的指针或者引用调用虚函数
b. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写
虚函数:
虚函数:即被virtual修饰的类成员函数称为虚函数。
classPerson{public:virtualvoidBuyTicket(){cout<<"买票-全价"<<endl;}};classPerson{public:virtualvoidBuyTicket(){cout<<"买票-全价"<<endl;}};classStudent:publicPerson{public:virtualvoidBuyTicket(){cout<<"买票-半价"<<endl;}voidFunc(Person&p){p.BuyTicket();}intmain(){Person ps;Student st;Func(ps);Func(st);return0;}注意:虚函数重写的两个例外:
classA{};classB:publicA{};classPerson{public:virtualA*f(){returnnewA;}};classStudent:publicPerson{public:virtualB*f(){returnnewB;}};//下⾯的代码我们可以看到,如果~A(),不加virtual,那么delete p2时只调⽤的A的析构函数,没有调⽤B的析构函数,就会导致内存泄漏问题,因为~B()中在释放资源。classA{public:virtual~A(){cout<<"~A()"<<endl;}};classB:publicA{public:~B(){cout<<"~B()->delete:"<<_p<<endl;delete_p;}protected:int*_p=newint[10];};// 只有派⽣类Student的析构函数重写了Person的析构函数,下⾯的delete对象调⽤析构函数,才能//构成多态,才能保证p1和p2指向的对象正确的调⽤析构函数。intmain(){A*p1=newA;A*p2=newB;deletep1;deletep2;return0;}C++11提供了override和final两个关键字,可以帮助用户检测是否重写。
classCar{public:virtualvoidDrive()final{}};classBenz:publicCar{public:virtualvoidDrive(){cout<<"Benz-舒适"<<endl;}};classCar{public:virtualvoidDrive(){}};classBenz:publicCar{public:virtualvoidDrive()override{cout<<"Benz-舒适"<<endl;}};classCar{public:virtualvoidDrive()=0;};classBenz:publicCar//纯虚函数也会被继承下来,重写虚函数后才可以被实例化{public:virtualvoidDrive(){cout<<"Benz-舒适"<<endl;}};classBMW:publicCar{public:virtualvoidDrive(){cout<<"BMW-操控"<<endl;}};voidTest(){Car*pBenz=newBenz;pBenz->Drive();Car*pBMW=newBMW;pBMW->Drive();}classBase{public:virtualvoidFunc1(){cout<<"Base:"<<"Func1()"<<endl;}protected:int_b=1;char_ch='x';};sizeof(Base)是多少?
通过观察测试我们发现b对象是16bytes,除了_b _ch 成员,还多一个__vfptr放在对象的前面(注意有些平台可能会放到对象的最后面,这个跟平台有关),对象中的这个指针我们叫做虚函数表指针(v代表virtual,f代表function)。一个含有虚函数的类中都至少都有一个虚函数表指针,因为虚函数的地址要被放到虚函数表中,虚函数表也简称虚表。
接着分析:
针对上面的代码我们做出以下改造
我们增加一个派生类Derive去继承Base
Derive中重写Func1
Base再增加一个虚函数Func2和一个普通函数Func3
classBase{public:virtualvoidFunc1(){cout<<"Base:"<<"Func1()"<<endl;}virtualvoidFunc2(){cout<<"Func2()"<<endl;}voidFunc3(){cout<<"Func3()"<<endl;}protected:int_b=1;char_ch='x';};classDerive:publicBase{public:virtualvoidFunc1(){cout<<"Derive:"<<"Func1()"<<endl;}private:int_d=2;};voidtest(){Base b;Derive d;}intmain(){test();return0;}
通过观察和测试:
classPerson{public:virtualvoidBuyTicket(){cout<<"买票-全价"<<endl;}};classStudent:publicPerson{public:virtualvoidBuyTicket(){cout<<"买票-半价"<<endl;}};voidFunc(Person&p){p.BuyTicket();}intmain(){Person Mike;Func(Mike);Student Johnson;Func(Johnson);return0;}