C++多态性

    xiaoxiao2022-06-24  31

    C++多态性 多态性是指向不同的对象发送同一个消息,不同对象对同一消息产生不同行为。即“一个接口,多种方法”。 一、编译多态(静态绑定)

    1)函数模板

    eg:

    #include <iostream> using std::cout; using std::endl; template <typename T> T max(const T& lsh, const T& rhs) { return (lsh >= rhs) ? lsh : rhs; } int main(int argc, char* argv[]) { int a = 3; int b = 4; cout << max(a, b) << endl;s float c = 2.4; float d = 1.2; cout << max(c, d) << endl; return 0; }运行结果: 4 2.4

    2)函数重载 函数名相同,但函数参数类型不同,参数个数不同或两者皆有。

    eg:

    #include <iostream> using std::cout; using std::endl; int max(int a, int b) { return (a > b) ? a : b; } int max(int a, int b, int c) { return max(max(a, b), c); } int main(int argc, char* argv[]) { int a = 3; int b = 4; int c = 5; cout << max(a, b) << endl; cout << max(a, b, c) << endl; return 0; }

    运行结果:

    4

    5

    3)运算符重载

    eg:

    #include <iostream> using std::cout; using std::endl; class A { public: A(int data) : data(data) {}; void show() { cout << "data = " << data << endl; } A operator+(const A& a) { return A(data + a.data); } private: int data; }; int main(int argc, char *argv[]) { A a1(100), a2(200); (a1 + a2).show(); return 0; }运行结果: data = 300

    二、运行多态(动态绑定) 1)虚函数 虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖,或者称为重写。 一个派生类用基类的指针表示,派生类和基类中有相同的函数名,相同的参数及相同的返回值。当用基类指针指向这些派生类对象时,系统会自动用派生类中的同名函数来代替基类中的虚函数。 只有类的成员函数才能声明为虚函数,全局函数及静态成员函数不能声明为虚函数。 虚函数声明格式:

    virtual 返回类型 函数名(形参表) { 函数体 } eg:

    #include <iostream> using std::cout; using std::endl; class Polygon { protected: int width, height; public: void set_values(int a, int b) { width = a; height = b; } virtual int area() { return 0; } }; class Rectangle : public Polygon { public: int area() { return width * height; } }; class Triangle : public Polygon { public: int area() { return (width * height / 2); } }; int main(int argc, char* argv[]) { Rectangle rect; Triangle trgl; Polygon poly; Polygon * ppoly1 = ▭ Polygon * ppoly2 = &trgl; Polygon * ppoly3 = &poly; ppoly1->set_values(4, 5); ppoly2->set_values(4, 5); ppoly3->set_values(4, 5); cout << ppoly1->area() << '\n'; cout << ppoly2->area() << '\n'; cout << ppoly3->area() << '\n'; return 0; }

    运行结果:

    20

    10

    0

    2)虚析构函数 如果在函数中用new建立一个派生类对象和定义一个基类对象指针,并将派生类对象的地址赋给基类对象指针时。当用delete运算符来撤销无名对象时,系统只执行基类析构函数,而不执行派生类析构函数。 如果要调用派生类的析构函数,则必须在基类的析构函数前加上virtual。 虚析构函数声明格式: virtual ~类名() { 函数体 } eg1: #include <iostream> using std::cout; using std::endl; class Graph { protected: double x; double y; public: Graph(double x, double y); virtual void showArea(); ~Graph(); }; Graph::Graph(double x, double y) { this->x = x; this->y = y; } void Graph::showArea() { cout << "计算图形面积" << endl; } Graph::~Graph() { cout << "调用图形类析构函数" << endl; } class Rectangle :public Graph { public: Rectangle(double x, double y) :Graph(x, y) {}; void showArea(); ~Rectangle(); }; void Rectangle::showArea() { cout << "计算矩形面积" << endl; } Rectangle::~Rectangle() { cout << "调用矩形类析构函数" << endl; } int main(int argc, char* argv[]) { Graph *graph; graph = new Rectangle(10, 5); graph->showArea(); delete graph; return 0; }

    运行结果:

    计算矩形面积

    调用图形类析构函数

    eg2:

    #include <iostream> using std::cout; using std::endl; class Graph { protected: double x; double y; public: Graph(double x, double y); virtual void showArea(); virtual ~Graph(); }; Graph::Graph(double x, double y) { this->x = x; this->y = y; } void Graph::showArea() { cout << "计算图形面积" << endl; } Graph::~Graph() { cout << "调用图形类析构函数" << endl; } class Rectangle :public Graph { public: Rectangle(double x, double y) :Graph(x, y) {}; void showArea(); ~Rectangle(); }; void Rectangle::showArea() { cout << "计算矩形面积" << endl; } Rectangle::~Rectangle() { cout << "调用矩形类析构函数" << endl; } int main(int argc, char* argv[]) { Graph *graph; graph = new Rectangle(10, 5); graph->showArea(); delete graph; return 0; }运行结果: 计算矩形面积 调用矩形类析构函数 调用图形类析构函数

    3)纯虚函数

    在基类中只声明虚函数而不给出具体的函数定义体,将它的具体定义放在各派生类中。通过该基类的指针或引用就可以调用所有派生类的虚函数,基类只是用于继承,仅作为一个接口,具体功能在派生类中实现。

    纯虚函数格式:

    virtual返回类型 函数名(形参表)=0;

    如果一个类中至少有一个纯虚函数,那么就称该类为抽象类。对于抽象类有以下几个注意点:

    (1)抽象类只能作为其他类的基类来使用,不能建立抽象类对象; (2) 不允许从具体类中派生出抽象类(不包含纯虚函数的普通类);

    (3)抽象类不能用作函数的参数类型、返回类型和显示转化类型;

    (4)如果派生类中没有定义纯虚函数的实现,而只是继承成了基类的纯虚函数。那么该派生类仍然为抽象类。一旦给出了对基类中虚函数的实现,那么派生类就不是抽象类了,而是可以建立对象的具体类。

    eg:

    #include <iostream> using std::cout; using std::endl; class Polygon { protected: int width, height; public: void set_values(int a, int b) { width = a; height = b; } virtual int area(void) = 0; }; class Rectangle : public Polygon { public: int area(void) { return (width * height); } }; class Triangle : public Polygon { public: int area(void) { return (width * height / 2); } }; int main(int argc, char* argv[]) { Rectangle rect; Triangle trgl; Polygon * ppoly1 = ▭ Polygon * ppoly2 = &trgl; ppoly1->set_values(4, 5); ppoly2->set_values(4, 5); cout << ppoly1->area() << '\n'; cout << ppoly2->area() << '\n'; return 0; }运算结果: 20 10

    4)虚表 虚函数通过一张虚函数表来实现的。此表为类的虚函数的地址表,通过此表解决继承、覆盖的问题,保证其真实反应实际的函数。为了保证取到虚函数表的最高的性能,编译器将虚函数表的指针存在于对象实例中最前面的位置。通过该对象实例的地址得到此虚函数表,然后遍历函数指针,从而调用相应的函数。

    (1)一般继承(无虚函数覆盖) a、虚函数按照其声明顺序放于表中 b、父类的虚函数在子类的虚函数前面 eg:

    #include <iostream> using std::cout; using std::endl; typedef void(*Fun)(void); class Base { public: virtual void f() { cout << "Base::f()" << endl; } virtual void g() { cout << "Base::g()" << endl; } virtual void h() { cout << "Base::h()" << endl; } }; class Derive :public Base { public: virtual void f1() { cout << "Derive::f1()" << endl; } virtual void g1() { cout << "Derive::g1()" << endl; } virtual void h1() { cout << "Derive::h1()" << endl; } }; int main(int argc, char* argv[]) { Derive b; Fun pFun = NULL; cout << "对象地址:" << (int*)(&b) << endl; cout << "虚函数表地址:" << (int*)*(int*)(&b) << endl; pFun = (Fun)*((int*)*(int*)(&b)); cout << pFun << endl; // Base::f() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 1); cout << pFun << endl; // Base::g() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 2); cout << pFun << endl; // Base::h() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 3); cout << pFun << endl; // Derive::f1() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 4); cout << pFun << endl; // Derive::g1() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 5); cout << pFun << endl; // Derive::h1() pFun(); return 0; }

    其运行结果:

    对象地址: 0041FAE0

    虚函数表地址: 01149B6C

    01141087

    Base::f()

    01141203

    Base::g()

    011410CD

    Base::h()

    0114102D

    Derive::f1()

    011413DE

    Derive::g1()

    01141334

    Derive::h1()

    其继承关系:

    其内存地址:

    其虚函数表:

    注:在上图中,虚函数表最后的一个结点是虚函数表的结束结点,类似于字符串的结束符“/0”。此标志的值在不同的编译器下是不同的,在Win7+VS2015下,此值为NULL;而在Ubuntu14+GCC下,此值如果为1,表示还有下一个虚函数表;如果为0,表示这是最后一个虚函数表。

    (2)一般继承(有虚函数覆盖)

    a、覆盖的函数被放到虚表中原来父类虚函数的位置

    b、没有被覆盖的函数依旧

    eg:

    #include <iostream> using std::cout; using std::endl; typedef void(*Fun)(void); class Base { public: virtual void f() { cout << "Base::f()" << endl; } virtual void g() { cout << "Base::g()" << endl; } virtual void h() { cout << "Base::h()" << endl; } }; class Derive :public Base { public: void f() { cout << "Derive::f()" << endl; } virtual void g1() { cout << "Derive::g1()" << endl; } virtual void h1() { cout << "Derive::h1()" << endl; } }; int main(int argc, char* argv[]) { Derive b; Fun pFun = NULL; cout << "对象地址:" << (int*)(&b) << endl; cout << "虚函数表地址:" << (int*)*(int*)(&b) << endl; pFun = (Fun)*((int*)*(int*)(&b)); cout << pFun << endl; // Base::f() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 1); cout << pFun << endl; // Base::g() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 2); cout << pFun << endl; // Base::h() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 3); cout << pFun << endl; // Derive::f1() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 4); cout << pFun << endl; // Derive::g1() pFun(); return 0; }其运行结果: 对象地址: 001AF7E8 虚函数表地址: 00D49B6C 00D41343 Derive::f() 00D411FE Base::g() 00D410C8 Base::h() 00D413DE Derive::g1() 00D4132F Derive::h1() 其继承关系:

    其内存地址:

    其虚函数表:

    (3)多重继承(无虚函数覆盖)

    a、每个父类都有自己的虚表

    b、子类的成员函数被被覆盖的放到父类

    eg:

    #include <iostream> using std::cout; using std::endl; typedef void(*Fun)(void); class Base1 { public: virtual void f() { cout << "Base1::f()" << endl; } virtual void g() { cout << "Base1::g()" << endl; } virtual void h() { cout << "Base1::h()" << endl; } }; class Base2 { public: virtual void f() { cout << "Base2::f()" << endl; } virtual void g() { cout << "Base2::g()" << endl; } virtual void h() { cout << "Base2::h()" << endl; } }; class Base3 { public: virtual void f() { cout << "Base3::f()" << endl; } virtual void g() { cout << "Base3::g()" << endl; } virtual void h() { cout << "Base3::h()" << endl; } }; class Derive :public Base1, public Base2, public Base3 { public: virtual void f1() { cout << "Derive::f1()" << endl; } virtual void g1() { cout << "Derive::g1()" << endl; } virtual void h1() { cout << "Derive::h1()" << endl; } }; int main(int argc, char* argv[]) { Derive b; Fun pFun = NULL; cout << "对象地址:" << (int*)(&b) << endl; cout << "虚函数表地址:" << (int*)*(int*)(&b) << endl; pFun = (Fun)*((int*)*(int*)(&b)); cout << pFun << endl; // Base1::f() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 1); cout << pFun << endl; // Base1::g() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 2); cout << pFun << endl; // Base1::h() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 3); cout << pFun << endl; // Derive::f1() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 4); cout << pFun << endl; // Derive::g1() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 5); cout << pFun << endl; // Derive::h1() pFun(); pFun = (Fun)*((int*)*((int*)(&b)+ 1)); cout << pFun << endl; // Base2::f() pFun(); pFun = (Fun)*((int*)*((int*)(&b) + 1) + 1); cout << pFun << endl; // Base2::g() pFun(); pFun = (Fun)*((int*)*((int*)(&b) + 1) + 2); cout << pFun << endl; // Base2::h() pFun(); pFun = (Fun)*((int*)*((int*)(&b) + 2)); cout << pFun << endl; // Base3::f() pFun(); pFun = (Fun)*((int*)*((int*)(&b) + 2) + 1); cout << pFun << endl; // Base3::g() pFun(); pFun = (Fun)*((int*)*((int*)(&b) + 2) + 2); cout << pFun << endl; // Base3::h() pFun(); return 0; }其运行结果: 对象地址:0036FCE4 虚函数表地址: 010E9C00 010E1339 Base1::f() 010E125D Base1::g() 010E12CB Base1::h() 010E1032 Derive::f1() 010E1406 Derive::g1() 010E1352 Derive::h1() 010E1005 Base2::f() 010E115E Base2::g() 010E13ED Base2::h() 010E10E1 Base3::f() 010E1037 Base3::g() 010E105A Base3::h()

      其继承关系:

    其内存地址:

    其虚函数表:

    (4) 多重继承(有虚函数覆盖)

    a、每个父类都有自己的虚表

    b、子类的成员函数被放到虚表中原来父类虚函数的位置

    c、没有被覆盖的依旧

    eg:

    #include <iostream> using std::cout; using std::endl; typedef void(*Fun)(void); class Base1 { public: virtual void f() { cout << "Base1::f()" << endl; } virtual void g() { cout << "Base1::g()" << endl; } virtual void h() { cout << "Base1::h()" << endl; } }; class Base2 { public: virtual void f() { cout << "Base2::f()" << endl; } virtual void g() { cout << "Base2::g()" << endl; } virtual void h() { cout << "Base2::h()" << endl; } }; class Base3 { public: virtual void f() { cout << "Base3::f()" << endl; } virtual void g() { cout << "Base3::g()" << endl; } virtual void h() { cout << "Base3::h()" << endl; } }; class Derive :public Base1, public Base2, public Base3 { public: void f() { cout << "Derive::f()" << endl; } virtual void g1() { cout << "Derive::g1()" << endl; } virtual void h1() { cout << "Derive::h1()" << endl; } }; int main(int argc, char* argv[]) { Derive b; Fun pFun = NULL; cout << "对象地址:" << (int*)(&b) << endl; cout << "虚函数表地址:" << (int*)*(int*)(&b) << endl; pFun = (Fun)*((int*)*(int*)(&b)); cout << pFun << endl; // Derive::f() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 1); cout << pFun << endl; // Base1::g() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 2); cout << pFun << endl; // Base1::h() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 3); cout << pFun << endl; // Derive::g1() pFun(); pFun = (Fun)*((int*)*(int*)(&b) + 4); cout << pFun << endl; // Derive::h1() pFun(); pFun = (Fun)*((int*)*((int*)(&b)+ 1)); cout << pFun << endl; // Derive::f() pFun(); pFun = (Fun)*((int*)*((int*)(&b) + 1) + 1); cout << pFun << endl; // Base2::g() pFun(); pFun = (Fun)*((int*)*((int*)(&b) + 1) + 2); cout << pFun << endl; // Base2::h() pFun(); pFun = (Fun)*((int*)*((int*)(&b) + 2)); cout << pFun << endl; // Derive::f() pFun(); pFun = (Fun)*((int*)*((int*)(&b) + 2) + 1); cout << pFun << endl; // Base3::g() pFun(); pFun = (Fun)*((int*)*((int*)(&b) + 2) + 2); cout << pFun << endl; // Base3::h() pFun(); return 0; }其运行结果: 对象地址: 0038F9DC 虚函数表地址: 00EC9C00 00EC136B Derive::f() 00EC1262 Base1::g() 00EC12D0 Base1::h() 00EC1410 Derive::g1() 00EC1357 Derive::h1() 00EC11DB Derive::f() 00EC1159 Base2::g() 00EC13F7 Base2::h() 00EC11E0 Derive::f() 00EC1032 Base3::g() 00EC1055 Base3::h() 其继承关系:

    其内存地址:

    其虚函数表:

    参考文献

    [1]C++ Virtual详解. http://www.cnblogs.com/xd502djj/archive/2010/09/22/1832912.html.

    [2] 浅谈C++多态性. http://blog.csdn.net/hackbuteer1/article/details/7475622.

    [3]C++之多态性与虚函数. http://www.cnblogs.com/CaiNiaoZJ/archive/2011/08/11/2134673.html.

    [4]C++多态性. http://zhidao.baidu.com/link?url=pjvK5KLQzRn5N_kAJjOf9CILsQoaxXjx8oIusE1gy26F9lIsgSzwcOcRux2qhA-uGHkJUfDNwaBe9gpGIxpfYq.

    [5]C++封装继承多态总结. http://blog.csdn.net/ruyue_ruyue/article/details/8211809.[6]C++多态的实现及原理详细解析. http://www.jb51.net/article/41809.htm.

    [7]C++虚函数、多态性与虚表. http://my.oschina.net/hnuweiwei/blog/280894.

    [8]Polymorphism. http://www.cplusplus.com/doc/tutorial/polymorphism/.

    [9]Polymorphism in c++. http://stackoverflow.com/questions/5854581/polymorphism-in-c.

    [10] 静多态. http://baike.baidu.com/link?url=Rjmg-K4ZCNMHSST_xCdJFhHufyChSixm1UJY4ibJHoI1PL4lhPRYnFchIyURFMFTD4wBUQonXsVWm517CaKUvq.

    [11]C++继承//多态. http://blog.csdn.net/pearl333/article/details/8056916.

    [12] C++ 虚函数表解析. http://blog.csdn.net/haoel/article/details/1948051.

     

    注:为了便于自己学习,无心侵权,尽可能。将所引用的文章列举出来;有些文章的内容可能会与原作重复度较高,还请谅解。如作者举报,愿意删除此文。

    转载请注明原文地址: https://ju.6miu.com/read-1123869.html

    最新回复(0)