C++多态


C++里的多态性主要有四种:

1)重载多态--------发生于同范围内,函数名相同,参数不同

2)包含多态--------“虚函数”实现的多态,发生于派生类与基类

3)强制多态--------为完成某功能进行类型的强制转换

4)参数多态--------“模板”反映的一种多态

 

这里我们主要讨论的是包含多态,后面就简称为多态。

     多态的表现就是同一个消息会引发不同的行为,实现“同一个接口,不同的方法”,但不同于函数重载的是它实现的是动态绑定,而函数重载实现的是静态绑定(动态绑定-------在程序运行期间确定函数调用的地址;静态绑定-------在程序编译阶段确定函数调用地址)动态绑定是OOP的很好的体现

   多态性是利用虚函数实现的。虚函数允许子类重新定义父类的方法,对父类方法进行覆盖override

   对于每个有虚函数的类来说,其都有一个虚表,该虚表存放了该类的虚函数指针,指向该类要调用的函数,每一个实例化的对象都有一个指向该虚表的指针,通过该指针访问到该对象的虚表,进而调用其函数

   现有如下代码:

class A

{

public:

   virtual fn()

   {

      cout <<"classA"<<endl;

   }

};

class B:public A

{

public:

   virtual fn()

   {

     cout<<"classB"<<endl;

   }

};

ClassB继承classA,那么classB同时也拥有了与classA一样的虚表,但是在classB的虚表中对fn()方法进行了覆盖,即用自己的方法将原父类方法覆盖掉了

因而 B b;  b.fn()会输出“classB”而不是“classA

 

以上就是包含多态实现的原理。

在这里插入一个问题?为什么虚函数是非静态

【答:静态函数属于整个对象,无this指针,但虚函数需要动态绑定来实现,程序运行过程中编译器根据对象的虚表指针查找虚表进而查找到虚函数的地址】

那么多态性有什么作用呢???

“封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。也就是说,不论传递过来的究竟是那个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。”引用一位高人所悟来解释这个问题我觉得甚是恰到好处

多态的使用一般都借助于父类的指针来实现,用父类的指针指向不同派生类的对象,借以实现根据其所指向对象调用具体函数,就是“一个接口,多种方法”的很好体现

与多态很容易混淆的C++的另一个特性就是“隐藏”,神一样的隐藏规则让很多人摸不着北

“隐藏”会发生在下面两种情况下:

1)子类与父类的同名函数参数不同不论有无virtual都会发生隐藏

2)子类与父类的同名函数参数相同但无virtual关键字

隐藏的表现就是,我子类明明没有覆盖掉基类的同名函数(多态)但子类

法访问到基类的那个同名函数,也就是子类隐藏掉了父类的同名函数

class A

{

public:

void fn1(int a)

{

   cout <<"classAfn1"<<endl;

}

void fn2(int x)

{

  cout <<"classAfn2"<<endl;

}

};

class B:public A

{

public:

void fn1(float f)

{

  cout<<"classBfn1"<<endl;

}

void fn2(int x)

{

  cout <<"classBfn2"<<endl;

}

};

int main(void)

{

   B b;

   A* pa = &b;

   B* pb = &b;

   //两个指针都指向同一块区域,按理调用产生的结果是相同的

 

   //我想调用基类的fn1(int)方法

   pa->fn1(3);//OK classA fn1

   pb->fn1(3);//surprise  classB fn1

   //我想调用子类的fn2(int)方法

   pa->fn2(2);//surprise classA fn2

   pb->fn2(1);//OK classB fn2

//结果取决于指针的类型

}



 

 

从上面代码可以看出,pb->fn1(3);我想用pb调用基类的方法却只能调用到自己的方法,访问不到父类的,父类的方法被隐藏掉了!!!

   还有一个与虚函数息息相关的概念就是“抽象类

class A

{

public:

       virtualvoid fn() = 0;

};

那么classA就是一个抽象类,不能实例化一个抽象类的对象,就像没有一个水果的名字叫水果一样,我们只有香蕉、苹果。。。

抽象类中的纯虚函数也就是上面代码中的fn()函数必须在抽象类的派生类中给出实现。

     抽象类更好的体现了OOP的封装及多态性,利于代码重用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值