zoukankan      html  css  js  c++  java
  • 12-继承与多态(下)

    一.重写与重载

       

    class Parent
    	{
    	public:
    		virtual  void func()
    		{
    			cout<<" void func()"<<endl;
    		}
    		virtual void func(int i)
    		{
    			cout<<" void func(int i)"<<endl;
    		}
    		virtual void func(int i,int j)
    		{
    			cout<<" void func(int i,int j)"<<endl;
    		}
    	};
    	
    class Child:public Parent
    {
    public:
    	virtual void func(int a,int b)
    	{
    		cout<<" void func(int a,int b)"<<endl;
    	}
    	virtual void func(int i,int j,int k)
    	{
    		cout<<" void func(int i,int j,int k)"<<endl;
    	}
    };	
    

        函数重载:

               (1)必须在同一类中,也就是在同一个作用域中。

               (2) 子类无法重载父类的函数。父类同名函数被覆盖

                  如: c.func();//错误,编译只是 

               (3)重载是在编译期间依据參数类型和个数决定调用函数的

        函数重写:
                (1) 必须发生在父类与子类之间

                (2) 而且父类与子类中的函数必须有全然同样的原型。

                (3) 使用 virtual 声明之后能顾产生多态

                (4) 多态是在执行期间依据详细对象的类型决定调用函数的

        对照: 一个是在编译期间决定的,一个是在执行期间决定的,所以重载的效率还是比重写的效率高。

     

    二. 对虚函数的理解

         C++中多态的实现原理

             (1) 当类中声明虚函数时,编译器会在类中生成一个虚函数表

             (2)  虚函数表是一个存储类成员函数指针的数据结构

             (3)  虚函数表是由编译器自己主动生成与维护的

             (4)  virtual 成员函数会被编译器放入虚函数表中

             (5) 存在虚函数时。每一个对象中都有一个指向虚函数表的指针。     



     

    void run(Parent* p)
    {
    	p->func(1,2);
    }

                   通过虚函数表指针VPTR调用重写函数是在程序执行时进行的,因此须要通过寻址操作才干确        定真正的应该调用的函数。

    而普通成员函数是在编译时就确定了调用的函数。

    在效率上。虚函数            的效率要低的多。

        注意: 处于效率的考虑,没有必要把全部的成员函数都声明为虚函数。

       对象中VPTR指针什么时候被初始化的?

            (1) 对象在创建的时候由编译器对VPTR指针进行初始化。

            (2) 仅仅有当对象的构造全然结束后VPTR的指向才终于确定

            (3) 父类对象的VPTR指向父类虚函数表

            (4) 子类对象的VPTR指向子类虚函数表

    class Parent
    {
    public:
    	Parent()
    	{
    		this->func();
    	}	
    	virtual void func()
    	{
    		cout<<"virtual void Parent::func()"<<endl;
    	}
    };
    
    class Child:public Parent
    {
    public:
    	Child()
    	{
    		func();
    	}
    	void func()
    	{
    		cout<<"void Child::func()"<<endl;
    	}	
    };
    
    int main()
    {
    	Child p;  
    	p.func();
    	return 0;
    }
    



         结论: 构造函数中调用虚函数无法实现多态

    三. 纯虚函数

         面向对象的抽象类

             (1) 抽象类可用于表示现实世界中的抽象概念

             (2) 抽象类是一种仅仅能定义类型,而不能产生对象的类

             (3) 抽象类仅仅能被继承并重写相关函数

             (4) 抽象类的直接特征是纯虚函数

          说明: 纯虚函数仅仅声明函数原型,不定义函数体的虚函数。

        抽象类与纯虚函数

              (1) 抽象类不能用于定义对象

              (2) 抽象类仅仅能用于定义指针和引用

              (3) 抽象中的纯虚函数必须被子类重写

    class Shape
    {
    public:
    	virtual double area()=0;
    };

        area是纯虚函数, =0 告诉编译器这个函数有益仅仅声明不定义。

    class Shape
    {
    public:
        virtual double area() = 0;
    };
    
    class Rectangle : public Shape
    {
        double m_a;
        double m_b;
    public:
        Rectangle(double a, double b)
        {
            m_a = a;
            m_b = b;
        }
        
        double area()
        {
            return m_a * m_b;
        }
    };
    
    class Circle : public Shape
    {
        double m_r;
    public:
        Circle(double r)
        {
            m_r = r;
        }
        
        double area()
        {
            return 3.14 * m_r * m_r;
        }
    };
    
    void area(Shape* s)
    {
        cout<<s->area()<<endl;
    }
    
    int main(int argc, char *argv[])
    {
        Rectangle rect(2, 3);
        Circle circle(4);
        
        area(&rect);
        area(&circle);
     	return 0;
    }
    

    小结:

          (1) 函数重载与函数重写不同

          (2) 多态是通过虚函数实现的

          (3) 虚函数在效率上会有影响

          (4) 抽象类是通过纯虚函数实现的。     





  • 相关阅读:
    [每天进步一点 流水账]第4周
    单指令流多数据流( SIMD)
    [每天进步一点 流水账]第2周
    写时复制技术(COW)
    ECMAScript 运算符乘性运算符
    ECMAScript 运算符Boolean 运算符
    ECMAScript 基础保留字
    ECMAScript 基础关键字
    ECMAScript 运算符一元运算符
    ECMAScript 基础原始类型
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5147632.html
Copyright © 2011-2022 走看看