C++学习六:多态、虚函数、虚函数的限制、成员函数覆盖,隐藏,重载、动态链接、虚函数表、抽象类、纯虚函数、虚继承、虚析构函数、限制构造函数

发布时间:2023年12月21日

一.多态

1.概念

? ? 因为个体差异,一个接口,多种实现方法;

2.虚函数

? ? 用virtual修饰的成员函数;

? ? eg:? ? ? ?

class Base{
? ? ? ? public:
? ? ? ? ? ? Base(int val) : val(val)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? ~Base()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? public:
? ? ? ? ? ? void prnmsg();
? ? ? ? ? ? void prnmsg(int i);
? ? ? ? private:
? ? ? ? ? ? int val;
? ? ? ? };
? ? ? ? void Base::prnmsg()
? ? ? ? {
? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? }
? ? ? ? void Base::prnmsg(int i)
? ? ? ? {
? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << ":" << i<< endl;
? ? ? ? }
class Inherit : public Base{
? ? ? ? public:
? ? ? ? ? ? Inherit(int val) : myval(val),Base(val)
? ? ? ? ? ? {
? ? ? ? ? ?? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? ~Inherit()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? void prnmsg()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? void prnmsg(int i)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << ":" << i<< endl;
? ? ? ? ? ? }
? ? ? ? private:
? ? ? ? ? ? int myval;
? ? ? ? };
? ? ? ? void test(Base &obj)
? ? ? ? {
? ? ? ? ? ? obj.prnmsg();
? ? ? ? }
? ? ? ? int main()
? ? ? ? { ?
? ? ? ? ? ? Base obja(123);
? ? ? ? ? ? Inherit objb(666);
? ? ? ? ? ? test(obja);
? ? ? ? ? ? test(objb);//Inherit -> Base
? ? ? ? ? ? return 0;
? ? ? ? }

3.虚函数的限制

? ? A、非类的成员函数不能定义为虚函数

? ? B、类的静态成员函数不能定义为虚函数

? ? C、构造函数不能定义为虚函数,但可以将析构函数定义为虚函数

? ? D、只需要在声明函数的类体中使用关键字“virtual”将函数声明为虚函数,而定义函数时不需要使用关键字“virtual”。

? ? E、当将基类中的某一成员函数声明为虚函数后,派生类中的同名函数(函数名相同、参数列表完全一致、返回值类型相关)自动成为虚函数。

二.重写、隐藏、重载

1.成员函数覆盖(override,也称重写)

? ? 是指派生类重新定义基类的虚函数,特征如下:

? ? A、不同的作用域(分别位于派生类与基类)

? ? B、函数名字相同

? ? C、参数相同

? ? D、基类函数必须有virtual关键字,不能有static

? ? E、返回值相同

? ? F、重写函数的权限访问限定符可以不同

2.成员函数重载(overload)

? ? 是指函数名相同,参数不同(数量、类型、次序),特征如下:

? ? A、相同的范围(在同一个作用域中)

? ? B、函数名字相同

? ? C、参数不同

? ? D、virtual 关键字可有可无

? ? E、返回值可以不同

3.成员函数隐藏(也称重定义)

? ? A、不在同一个作用域(分别位于派生类与基类)

? ? B、函数名字相同

? ? C、返回值可以不同

? ? D、参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意与重载的区别)

? ? E、参数相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意与覆盖的区别)

? ? eg:

? ? ? ? //1 2关系:函数重载

? ? ? ? //1 3关系:重写

? ? ? ? //2 4关系:隐藏
? ? ?

class Base{
            public:
                Base(int val) : val(val)
                {
                    cout << __func__ << ":" << __LINE__ << endl;
                }
                ~Base()
                {
                    cout << __func__ << ":" << __LINE__ << endl;
                }
            public:
                virtual void prnmsg();//prnmsg是虚函数  1
                void prnmsg(int i);  //                 2

            private:
                int val;
        };

        void Base::prnmsg()
        {
            cout << __func__ << ":" << __LINE__ << endl;
        }
        void Base::prnmsg(int i)
        {
            cout << __func__ << ":" << __LINE__ << ":" << i<< endl;
        } 

        class Inherit : public Base{
            public:
                Inherit(int val) : myval(val),Base(val)
                {
                    cout << __func__ << ":" << __LINE__ << endl;
                }
                ~Inherit()
                {
                    cout << __func__ << ":" << __LINE__ << endl;
                }

                void prnmsg()//虚函数:子类重写基类的虚函数    3
                {
                    cout << __func__ << ":" << __LINE__ << endl;
                }
                void prnmsg(int i) //                         4
                {

                    cout << __func__ << ":" << __LINE__ << ":" << i<< endl;
                }

            private:
                int myval;
        };

        void test(Base &obj)
        {
            obj.prnmsg();//虚函数是动态链接:在运行时由对象决定调用的函数,即对象是Base,则调用Base::prnmsg() ,否则,调用Inherit::prnmsg()
            obj.prnmsg(123);
        }
        int main()
        {	
            Base obja(123);
            Inherit objb(666);
            test(obja);
            test(objb);//Inherit -> Base
            return 0;
        }

三.动态链接

1.联编(链接)

? ? 就是将模块或者函数合并在一起生成可执行代码的处理过程。按照联编所进行的阶段不同,可分为两种不同的联编方法:静态联编和动态联编。

2.静态联编(静态链接)

? ? 是指在编译阶段就将函数实现和函数调用关联起来,因此静态联编也叫早绑定。

3.动态联编(动态链接)

? ? 是指在程序执行的时候才将函数实现和函数调用关联,因此也叫运行时绑定或者晚绑定。C++中一般情况下联编也是静态联编,但是一旦涉及到多态和虚拟函数就必须要使用动态联编了。

4.虚函数表技术

? ? 基类的虚函数表登记的是基类的虚函数

? ? 子类的虚函数表登记的是子类的虚函数

? ? eg:? ? ?

class Base{
? ? ? ? public:
? ? ? ? ? ? virtual void funa(void)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }

? ? ? ? ? ? virtual void funb(void)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? };

class Inherit : public Base{
? ? ? ? public:
? ? ? ? ? ? void funa(void)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? void funb(void)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? };
? ? typedef void (*PFUNC) (void);//函数指针

? ? int main()
? ? {
? ? ? ? Base obj;
? ? ? ? long vaddr = *(long *)&obj;//得到虚函数表的首地址
? ? ? ? PFUNC fun = ?(PFUNC)*(long *)vaddr;//得到虚函数表中登记的第一个虚函数的首地址
? ? ? ? fun();//调用funa()
? ? ? ? fun = ?(PFUNC)*((long *)vaddr + 1);//得到虚函数表中登记的第一个虚函数的首地址
? ? ? ? fun();
? ? ? ? return 0;
? ? }

四.抽象类

1.概念

? ? 有纯虚函数的类叫抽象类;

2.纯虚函数

? ? virtual ?返回值类型 函数名(参数列表) = 0;

3.抽象类

? ? 含有纯虚函数的类就是抽象类。

? ? 抽象类,没有完整的信息只能是派生类的基类

? ? 抽象类不能有实例,不能有静态成员

? ? 派生类应该实现抽象类的所有方法

?

? ? eg:抽象类? ? ? ?

 class Graphic{
? ? ? ? public:
? ? ? ? ? virtual double area(void) = 0;//纯虚函数 在派生类中实现
? ? };

class Circle : public Graphic{
? ? ? ? public:
? ? ? ? ? ? Circle(double r) : r(r)
? ? ? ? ? ? {

? ? ? ?
? ? ? ? ? ? }
? ? ? ? public:
? ? ? ? ? ? double area(void) //重写基类的纯虚接口
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return r*r*3.14;
? ? ? ? ? ? }
? ? ? ? private:
? ? ? ? ? ? double r;
? ? };
? ? int main()
? ? {
? ? ? ? Graphic obja;//error 抽象类不能有对象
? ? ? ? Circle objb(5);
? ? ? ? cout << objb.area() << endl;
? ? ? ? return 0;
? ? }

?五.虚继承

1.原理

? ? C++使用虚拟继承(Virtual Inheritance),解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类,这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。

2.解决

? ? 解决多重继承产生的二义性

eg:?

? class Base{
? ? ? ? public:
? ? ? ? ? ? Base()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? ~Base()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? public:
? ? ? ? ? ? void prnmsg()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? };


class Man : public virtual Base{//虚继承:解决多重继承产生的二义性
? ? ? ?public:
? ? ? ? ? ? Man()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? ~Man()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? };

class Wolf :public virtual Base{
? ? ? ? public:
? ? ? ? ? ? Wolf()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? ~Wolf()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? };

? ? //多重继承
class WolfMan : public Wolf,public Man{
? ? ? ? public:
? ? ? ? ? ? WolfMan()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? ~WolfMan()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? };
? ? int main()
? ? {
? ? ? ? WolfMan obj;
? ? ? ? obj.prnmsg();//多重继承产生二义性
? ? ? ? return 0;

? ? }

?六.虚析构函数

1.析构函数应该定义为虚析构

eg:? ?

class Base{
? ? ? ? public:
? ? ? ? ? ? Base(int val=0) : val(val)
? ? ? ? ? ? {
? ? ? ? ? ? ? ?cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? virtual ~Base()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? private:
? ? ? ? ? ? int val;
? ? };

class Inherit : public Base{
? ? ? ? public:
? ? ? ? ? ? Inherit(int val = 0) : myval(val)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? ? ? ~Inherit()//基类析构为虚时,子类析构自动为虚
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ << endl;
? ? ? ? ? ? }
? ? ? ? private:
? ? ? ? ? ? int myval;
? ? };

? ? int main()
? ? { ?
? ? ? ? Base *p = new Inherit;//类型转换 Inherit * - > Base *
? ? ? ? delete p;//子类对象析构时,基类也会被析构
? ? ? ? return 0;

? ? }

七.限制构造函数

1.概念

? ? 构造函数的权限不是public,这样的构造函数叫限制构造函数。

? ? eg1:? ? ? ?

class Base{
? ? ? ? protected:
? ? ? ? ? ? Base() //限制构造函数
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ <<endl;
? ? ? ? ? ? }
? ? ? ? public:
? ? ? ? ? ? ~Base()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ <<endl;
? ? ? ? ? ? }
? ? ? ? };

? ? ? ?
class Inherit : public Base{
? ? ? ? public:
? ? ? ? ? ? Inherit()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ <<endl;
? ? ? ? ? ? }
? ? ? ? ? ? ~Inherit()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ <<endl;
? ? ? ? ? ? }
? ? ? ? };

? ? ? ? int main()
? ? ? ? {
? ? ? ? ? ? Base obj;//error
? ? ? ? ? ? Inherit obj;//right
? ? ? ? ? ? return 0;

? ? ? ? }

? ? eg2:? ? ? ?

class Demo{
? ? ? ? private:
? ? ? ? ? ? Demo() //限制构造函数
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ <<endl;
? ? ? ? ? ? }

? ? ? ? public:
? ? ? ? ? ? ~Demo()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cout << __func__ << ":" << __LINE__ <<endl;
? ? ? ? ? ? }
? ? ? ? friend Demo *getobj(void);
? ? ? ? friend void freeobj(Demo *p);
? ? };

? ? Demo *getobj(void)
? ? {
? ? ? ? Demo *p = new Demo;
? ? ? ? return p;
? ? }

? ? void freeobj(Demo *p)
? ? {
? ? ? ? delete p;
? ? }

? ? int main()
? ? {
? ? ? ? Demo *p = getobj();
? ? ? ? freeobj(p);
? ? ? ? return 0;
? ? }

文章来源:https://blog.csdn.net/only_write_bug/article/details/135133924
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。