zoukankan      html  css  js  c++  java
  • C++--第19课

    第19课 - 专题三经典问题解析

    1. 当多态遇见对象数组会发生什么?

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    class Parent

    {

    protected:

        int i;

    public:

        virtual void f()

        {

            cout<<"Parent::f"<<endl;

        }

    };

    //sizeof(Parent) = 8,int i占四个字节,虚函数占四个字节。

    class Child : public Parent

    {

    protected:

        int j;

    public:

        Child(int i, int j)

        {

            this->i = i;

            this->j = j;

        } 

        void f()

        {

            cout<<"i = "<<i<<" "<<"j = "<<j<<endl;

        }

    };

    //sizeof(child) = 12,继承来int i四个字节,自己又定义四个字节,虚函数表四个字节

    int main(int argc, char *argv[])

    {

        Parent* p = NULL;

        Child* c = NULL;

        Child ca[3] = {Child(1, 2), Child(3, 4), Child(5, 6)};

        p = ca;  //赋值兼容性原理 ,数组名就是第一个元素的地址  i=1,j=2

        c = ca;  //i=1,j=2

        cout<<hex<<p+1<<endl;

        p->f();  //f是个重写函数 ,发生了多态,要根据实际的情况来判定用的那个函数。

             //这行有误

        c->f();  

        p++; //指向数组中的第二个对象

        c++;

     //   p->f();

      //  c->f();

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    不要将多态应用于数组。指针运算是通过指针的类型进行的。多态通过虚函数表实现的。

    指针运算是编译器根据指针的类型来进行的,多态是在运行的时候通过虚函数表查询来进行的。这两种实现方式是不同的。多态是程序运行的时候动态的查找函数的。

    l  多态与指针的混搭的结果

     

    我们看ca[0]的长度是12,只有12个字节长度的指针才能与它合理搭配。

    结论:

    不要在数组上使用多态。

    2. 为什么没有讲解多重继承

    C++在语法上是支持多重继承的。

     

    l  被实际开发经验抛弃的多继承

    工程开发中真正意义上的多继承是几乎不被使用的。

    多重继承带来的代码复杂性远多于其带来的便利。

    多重继承对代码的维护性上的影响是灾难性的。

    再设计方法上,任何多继承都可以用单继承来代替。

    3. 多继承复杂性示例

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    class Object

    {

    protected:

        int d;

    public:

        void f()

        {

            cout<<"Object::f"<<endl;

        }

    };

    class P1 : public Object

    {

    protected:

        int i;

    };

    class P2 : public Object

    {

    protected:

        int j;

    };

    class Child : public P1, public P2

    {

    public:

        Child(int i, int j)

        {

            this->d = 0; //二义性 ,child不是直接继承的object,而是间接的,有了两个d

            this->i = i;

            this->j = j;

        }

        void print()

        {

            cout<<"i = "<<i<<" "<<"j = "<<j<<endl;

        }

    };

    int main(int argc, char *argv[])

    {

        Child c(1, 2);

        c.print();

        c.f();  //同样有二义性,不知道是从哪里来的,继承只能感受到,直接的父类。

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    在只有单继承的系统中,类之间的继承关系为一棵树。

    在引入多重继承的系统中,类之间的继承关系呈现为一张图。

     

    l  C++中对多继承二义性的解决方案

    虚继承:

    为了解决从不同途径继承来的同名数据成员造成的二义性问题,可以将共同的基类设置为虚基类。这是从不同的路径继承过来的同名数据成员在内存中就有一个拷贝。

    这样做,实际上是治标不治本,只会使得在工程中更加麻烦。

    class P1 : virtual public Object

    {

    protected:

    int i;

    };

    class P2 : virtual public Object

    {

    protected:

    int j;

    };

    在实际的工程中的类是成百上千的,所以我们实际工作中尽量少使用多继承。虚函数是很占用空间的,不写又会怀疑。

    4. C++是否有Java中接口的概念

    绝大多数面向对象的语言都不支持多继承。

    绝大多数面向对象语言都支持接口的概念。

    C++中没有接口的概念。

    C++中可以使用虚函数来实现接口

    class Interface

    {

    public:

    virtual void func1() = 0;

    virtual void func2(int i) = 0;

    virtual void func3(int i, int j) = 0;

    };

    实际的工程经验证明。多重继承接口不会带来二义性和复杂性等问题。多重继承可以通过精心设计用单继承和接口来代替。

    接口只是一个功能说明,而不是功能实现。子类需要根据功能说明定义功能实现。

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    class Interface1  //第一个接口

    {

    public:

        virtual void print() = 0;

        virtual int add(int i, int j) = 0;

    };

    struct Interface2  //第二个接口

    {

        virtual int add(int i, int j) = 0;

        virtual int minus(int i, int j) = 0;

    };

    class Child : public Interface1, public Interface2

    {

    public: 

        void print()

        {

            cout<<"Child::print"<<endl;

        }

        int add(int i, int j)

        {

            return i + j;

        }

        int minus(int i, int j)

        {

            return i - j;

        }

    };

    int main(int argc, char *argv[])

    {

        Child c;

        c.print();

        cout<<c.add(3, 5)<<endl;

        cout<<c.minus(4, 6)<<endl;

        Interface1* i1 = &c;

        Interface2* i2 = &c;

        cout<<i1->add(7, 8)<<endl;

        cout<<i2->add(7, 8)<<endl;

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    运行结果:

    Child::print

    8

    -2

    15

    15

    专题三中的多态是实现设计模式的基本技术!

  • 相关阅读:
    Windows XP下 Android开发环境 搭建
    Android程序的入口点
    在eclipse里 新建android项目时 提示找不到proguard.cfg
    64位WIN7系统 下 搭建Android开发环境
    在eclipse里 新建android项目时 提示找不到proguard.cfg
    This Android SDK requires Android Developer Toolkit version 20.0.0 or above
    This Android SDK requires Android Developer Toolkit version 20.0.0 or above
    Android requires compiler compliance level 5.0 or 6.0. Found '1.4' instead
    Windows XP下 Android开发环境 搭建
    Android程序的入口点
  • 原文地址:https://www.cnblogs.com/free-1122/p/11336236.html
Copyright © 2011-2022 走看看