欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > c/c++ >内容正文

c/c++

C++:类-多态的学习和使用

发布时间:2025/3/20 c/c++ 36 豆豆
生活随笔 收集整理的这篇文章主要介绍了 C++:类-多态的学习和使用 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

C++:类的学习和使用

  • 类的多态
  • 1.类的实例化
  • 1.类中虚函数的使用实现多态
  • C++ override使用详解

类的多态

类作用域操作符 ::

C++是面向对象的编程语言,多态的使用是父类与子类关系最直接的表现:
c++中对于多态的理解就好比如下一个例子:
①我们说一种有四条腿的动物A,并进行简单描述有四条腿的特征;
②甲猜了一种动物B,并且说了四条腿的具体特征;
③乙猜了一种动物C,并且说了四条腿的具体特征;

如上:动物A可以理解为基类,动物B.C都是子类,所以类的多态就表现在四条腿的特征(父类的(纯)虚函数)上 B和C都继承了A四条腿的特征,至于B和C因为各自物种差异而有所不同就对应了具体的子类中的(纯)虚函数定义。

https://blog.csdn.net/lling_shan/article/details/105947287
分类:
静态多态
:静态多态是编译器在编译期间完成的,编译器会根据实参类型来选择调用合适的函数,如果有合适的函数可以调用就调,没有的话就会发出警告或者报错。
动态多态
:程序运行时根据基类的引用(指针)指向的对象来确定自己具体该调用哪一个类的虚函数

静态多类:

/** 程序名:book236.cpp,此程序用于演示C++类的静态多态。* 作者:C语言技术网(www.freecplus.net) 日期:20190525 */ #include <stdio.h> #include <string.h>class CGirl // 定义超女类 { public:char m_name[50]; // 姓名int m_age; // 年龄int m_height; // 身高,单位:厘米cmchar m_sc[30]; // 身材,火辣;普通;飞机场。char m_yz[30]; // 颜值,漂亮;一般;歪瓜裂枣。int Show() // 显示超女基本信息的成员函数体{ printf("姓名:%s,年龄:%d,身高:%d,身材:%s,颜值:%s\n",m_name,m_age,m_height,m_sc,m_yz); } };class CKCon:public CGirl // 定义王妃类,从超女类继承 { public:char m_ch[50]; // 称号char m_palace[50]; // 居住的宫殿int m_sal; // 奉禄int Show() // 显示王妃的称号、宫殿和奉禄{ printf("姓名:%s,称号:%s,栖:%s,奉禄:%d两银子。\n",m_name,m_ch,m_palace,m_sal); } };int main() {CKCon KCon;strcpy(KCon.m_name,"杨玉环"); KCon.m_age=28; KCon.m_height=168;strcpy(KCon.m_sc,"火辣"); strcpy(KCon.m_yz,"漂亮"); strcpy(KCon.m_ch,"杨贵妃");strcpy(KCon.m_palace,"华清宫"); KCon.m_sal=10000;CGirl *pGirl; // 基类的指针CKCon *pCon; // 派生类的指针pGirl=pCon=&KCon; // 都指向派生类pGirl->Show(); // 将调用的是基类的Show方法pCon->Show(); // 将调用的是派生类的Show方法 }

输出结果:

main函数中,创建的是CKCon对象,如果采用基类指针调用Show方法,变成了调用CGirl类的Show方法,而不是CKcon类的Show方法,因为pGirl是CGirl的指针,pGirl->Show方法在程序编译期间就已经设置好了。

动态多态:
动态多态是在程序运行时根据基类的引用(指针)指向的对象来确定自己具体该调用哪一个类的虚函数。

让我们对程序稍作修改,在CGirl类中,Show方法的声明前放置关键字 virtual,如下所示:

virtual int Show() // 显示超女基本信息的成员函数体

其它的代码都不变,编译并运行,结果如下:

此时,编译器看的是指针的内容,而不是它的类型。这就是多态的一般使用方式。

1.类的实例化

https://blog.csdn.net/qq_34637408/article/details/71189382

1.类中虚函数的使用实现多态

①类的多态
②1.首先看成员函数所在的类是否会作为基类。然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该将它声明为虚函数。

  • 如果成员函数在类被继承后功能不需修改,或派生类用不到该函数,则不要把它声明为虚函数。不要仅仅考虑到要作为基类而把类中的所有成员函数都声明为虚函数。
  • 3、应考虑对成员函数的调用时通过对象名还是通过基类指针或引用去访问,如果是通过基类指针或引用去访问的,则应当声明为虚函数。

    4.有时,在定义虚函数时,并不定义去函数体,即函数体是空的。它的作用只是定义了一个虚函数名,具体功能留给派生类去添加。

    使用虚函数,系统要有一定的空间开销。当一个类带有虚函数时,编译系统会为该类构造一个虚函数表,它是一个指针数组,存放每个虚函数的入口地址。系统在进行动态关联时的时间开销时很小的,因此,多态性时高效的。

    原文链接:https://blog.csdn.net/wshngyf/article/details/48092679

    纯虚函数

    一、定义
      纯 虚函数 是一种特殊的虚函数,它的一般格式如下:

    class <类名>{virtual <类型><函数名>(<参数表>)=0;};

    在许多情况下,在基类中不能对虚函数给出有意义有实现,而把它说明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。
      
    二、引入原因
      1、为了方便使用 多态 特性,我们常常需要在基类中定义虚拟函数。
      2、在很多情况下,基类本身生成对象是不合情理的。
      例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
      为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重载以实现多态性。同时含有纯虚拟函数的类称为 抽象类 ,它不能生成对象。这样就很好地解决了上述两个问题。
    三、相似概念
      1、多态性
      指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。
      C++支持两种多态性:编译时多态性,运行时多态性。
      a.编译时多态性:通过重载函数实现
      b 运行时多态性:通过虚函数实现。

      2、虚函数
      虚函数是在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态重载
      3、抽象类
      包含纯虚函数的类称为抽象类
      由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。
      
    注意:
    (1)纯虚函数没有函数体;
    (2)最后面的“=0”并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是虚函数”;
    (3)这是一个声明语句,最后有分号。
    纯虚函数只有函数的名字而不具备函数的功能,不能被调用。
    纯虚函数的作用是在基类中为其派生类保留一个函数的名字,以便派生类根据需要对他进行定义。如果在基类中没有保留函数名字,则无法实现多态性。
    如果在一个类中声明了纯虚函数,在其派生类中没有对其函数进行定义,则该虚函数在派生类中仍然为纯虚函数。

    抽象类:
    不用定义对象而只作为一种基本类型用作继承的类叫做抽象类(也叫接口类),凡是包含纯虚函数的类都是抽象类,抽象类的作用是作为一个类族的共同基类,为一个类族提供公共接口,抽象类不能实例化出对象。
    纯虚函数在派生类中重新定义以后,派生类才能实例化出对象。
    总结:
    1、派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同。(协变除外)
    2、基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。
    3、只有类的非静态成员函数才能定义为虚函数,静态成员函数不能定义为虚函数。
    4、如果在类外定义虚函数,只能在声明函数时加virtual关键字,定义时不用加。
    5、构造函数不能定义为虚函数,虽然可以将operator=定义为虚函数,但最好不要这么做,使用时容易混淆
    6、不要在构造函数和析构函数中调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会出现未定义的行为。
    7、最好将基类的析构函数声明为虚函数。(析构函数比较特殊,因为派生类的析构函数跟基类的析构函数名称不一样,但是构成覆盖,这里编译器做了特殊处理)
    8、虚表是所有类对象实例共用的虚表剖析。

    原文链接:https://blog.csdn.net/qq_36221862/article/details/61413619

    class A{public:A();virtual ~A();void f1();virtual void f2();virtual void f3()=0;};//子类:class B : public A{public:B();virtual ~B();void f1();virtual void f2();virtual void f3();};// main 函数:int main(int argc, char* argv[]){A *m_j=new B();m_j->f1();m_j->f2();m_j->f3();delete m_j;return 0;}

    f1()是一个隐藏,关于函数的隐藏,可以参考其它词条.
    调用m_j->f1();会去调用A类中的f1(),它是在我们写好代码的时候就会定好的.
    也就是根据它是由A类定义的,这样就调用这个类的函数.
    f2()是普通的重载.
    调用m_j->f2();会调用m_j中到底保存的对象中,对应的这个函数.这是由于new的B对象.
    f3()与f2()一样,只是在基类中不需要写函数实现.

    虚函数和抽象基类的应用:

    #include <iostream> using namespace std;//声明抽象基类Shape class Shape { public:virtual float area()const //虚函数{return 0.0;}virtual void shapeName()const = 0;//纯虚函数//shapeNamea函数的作用是输出具体的形状,在派生类中定义,因此声明为纯虚函数 };//声明Point类 class Point:public Shape { public:Point(float a = 0.0, float b = 0.0){x = a;y = b;}void setPoint(float a, float b){x = a;y = b;}float getX()const{return x;}float getY()const{return y;}virtual void shapeName()const{cout<<"Point:";}friend ostream & operator <<(ostream &_cout, const Point &p){_cout<<"["<<p.x<<","<<p.y<<"]";return _cout;}protected:float x;float y; };//声明Ciircle类 class Circle:public Point { public:Circle(float a = 0.0, float b = 0.0, float r = 0.0):Point(a, b),radius(r){}void setRadius(float r){radius = r;}float getRadius()const{return radius;}virtual float area()const{return 3.1415926*radius*radius;}virtual void shapeName()const{cout<<"Circle:";}friend ostream & operator <<(ostream &_cout, const Circle &c){_cout<<"["<<c.x<<","<<c.y<<"],r="<<c.radius;return _cout;}protected:float radius; };int main() {Point point(3.2, 4.5); // 建立Point类对象pointCircle circle(2.4, 1.2, 5.6); //建立Circle类对象circlepoint.shapeName(); //静态关联cout<<point<<endl;circle.shapeName(); //静态关联cout<<circle<<endl;Shape* pt; //定义基类指针pt = &point;pt->shapeName();cout<<"x="<<point.getX()<<",y="<<point.getY()<<endl;cout<<"area="<<pt->area()<<endl;pt = &circle; //指针指向Circle类对象pt->shapeName(); //动态关联cout<<"x="<<circle.getX()<<",y="<<circle.getY()<<endl;cout<<"area="<<pt->area()<<endl;system("pause");return 0; }

    运行结果

    结论:
    (1)一个基类如果包含一个或一个以上纯虚函数,就是抽象基类。抽象基类不能也没必要定义对象。
    (2)在类的层次结构中,顶层或最上面几层可以是抽象基类。抽象基类体现了本类族中各类的共性,把各类中共有的成员函数集中在抽象基类中声明。
    (3)抽象基类是本类族的共公共接口,即就是从同一基类中派生出的多个类有同一接口。

    原文链接:https://blog.csdn.net/qq_36221862/article/details/61413619

    C++ override使用详解

    C++ override从字面意思上,是覆盖的意思,实际上在C++中它是覆盖了一个方法并且对其重写,从而达到不同的作用。在我们C++编程过程中,最熟悉的就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。还有一个典型应用就是在继承中也可能会在子类覆盖父类的方法。

    原文链接:https://blog.csdn.net/fanyun_01/article/details/79122136

    总结

    以上是生活随笔为你收集整理的C++:类-多态的学习和使用的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。