首页 > 代码库 > 12-继承与多态(下)

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) 抽象类是通过纯虚函数实现的。     





12-继承与多态(下)