为何需要虚函数 直接对象名加作用域来调用子类父类爷类的函数不就行了 为啥

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为何需要虚函数 直接对象名加作用域来调用子类父类爷类的函数不就行了 为啥相关的知识,希望对你有一定的参考价值。

父类只有一种特征,加上虚函数以后子类通过继承父类并重写虚函数每一个子类就会有另一种特征,这么做可以减少代码量,避免重复代码,就跟你说的一样,比如说:

class Light

public:
 virtual  void  light_on()
 
      //假设这里有十万行代码让灯亮起来
 
;
class Red_Light : public Light

public:
 void light_on()    //重写亮灯函数
 
      //现在我只需要写几十行代码让灯变成红色  
      Light::light_on();//以此替代了十万行代码
 ;

当然,这只是一种,虚函数还体现了C++的多态性和抽象性(纯虚函数)。

追问

我是说 建立一个子类对象。

然后对象::作用域

这样不就可以调用任意的父类爷类函数了?

不知道虚函数到底是干什么用

追答

你说的当然可以。
父类对象::函数 必然可以调用父类函数,这没错,那现在我说说虚函数的存在意义。
首先虚函数是在前面加 virtual ,可以被子类重写而不是覆盖父类函数,要在父类声明。

举个栗子:

所谓的 “食物” 这个抽象的玩意可以看成一个父类,因为你想到食物只会想到苹果、香蕉这些子类。
因为你无法描述 "食物" 这个东西到底实际是个啥玩意,它是抽象的,只有定义:
可以放到嘴里面吃的东西(这可以看成一个 ”吃“ 函数)。

然后在看苹果(一个“食物”的子类),当我要吃苹果的时候,我直接调用父类的“吃”函数,放到嘴里,很甜。
然后在看猪肉(一个”食物“的子类),当我要吃猪肉的时候,我直接调用父类的”吃“函数,放到嘴里,草,我是野人吗?

不知道你懂了没有,虚函数可以重写,也就是说父类的一些方法放到子类没办法用,不合逻辑,当然我就需要重写这个方法,往这个方法上添加子类独特的特性,这就是虚函数存在的意义。

追问

反正虚函数就是,本来调用父类的,变成调用子类的。

假设c是子类对象。 c.A::函数名就能调用爷类。当然如果要调用子类函数那不是更简单?

总之,想调用哪个就调用哪个。

你说以食物为入口来调用苹果?从实际角度来说,调用父类虚函数不就等于调用子类哪个函数么

追答

所谓的调用父类虚函数要看实际的实例是什么。

苹果可以是 “食物“,猪肉也可以是”食物“。

所以以一个”食物“可以代替苹果和猪肉,但是当需要 "吃" 食物的时候,当”食物“ 是代指苹果的时候就直接吃,当代指猪肉的时候就 红烧或者炖来吃,换成代码就是

class Food

public:
 virtual  void eat()
 
  //放入口中
 
;

  
class Apple : public Food

public:
 void eat()
 
  Food::eat();
 
;

  
class Meat : public Food

public:
 void eat()
 
  //先红烧
  Food::eat();
 
;

int main()

 Food *food=NULL;  //一个食物的抽象对象
 
 food = new Apple; // 此时食物是苹果
 food->eat();      //直接吃
 delete food;
 
 food = new Meat; //此时食物是肉
 food->eat();     //红烧肉
 food->Food::eat(); //当然,如果你是野人的话。
 delete food;
 
 return 0;

注意我两次调用了同一个方法,但是出来结果是不一样的。

追问

我知道结果不一样啊,看来你还不是不明白我的意思。

你所谓的food->eat(); 不就是调用子类函数么?父类的虚函数干什么用?不就是让他调用子类函数么?这跟直接去调用不是一样?

你调用了两次,当然不一样。写法上一样但一个是apple函数一个是meat函数。

至于最后的野人,那是调用父类啊!你food->Meat::eat();不就行了?如果不行,那别用这种以小指大的指针啊

追答

上面说的就是多态性,如果你连抽象和多态都还没明白,那我再怎么跟你讲都是白讲。
Windows最基本的COM接口,你甚至连它的子类叫什么名字都不知道,给你的只有纯虚抽象类加API函数加一大堆dll,那你如何构造子类去直接调用子类函数?当我说钱的时候你知道我说的是什么钱?当我说买东西花了多少钱你知道我花的什么钱?美元?欧元?RMB?
如果连这都不清楚那我请问你你为什么要派生子类?直接全部用一个单独的类做到底不是更好?为什么要用C++?直接用函数做不是更快?

参考技术A 小明的爷爷创了霍家拳,传给了小明他爸
他爸爸改进了下创造了霍家拳改进版,传给小明,
小明也改进了下霍家拳改进版。

但是小明家有规定,霍家拳是爷爷创的,他有版权的,没有他的同意,你只能用爷爷版的霍家拳,不能用自己改进的霍家拳的(爸爸和小明都不能用的)。
大家让小明展示功夫,小明说没有爷爷给我个virtual的授权令,我只能打爷爷的原版权,就不能打我自己的改进版的了。

virtual就是一个授权,爷爷说了virtual,爸爸和小明就可以对外表现自己改进的霍家拳了,不然他们是不可以的。这样才实现了多态。

具体的指针这些更加深入的,你自己看c++ primer吧,没有比他讲的更清楚的了

对了他的名字应该叫霍小明。。。追问

我说用作用域可以调用任意的子类父类爷类的函数。

你说改进版?哪里有什么改进版的?把子类跟父类融合的?

无非就是本身函数跟继承的函数。

用子类对象名::作用域 这样可以任意调用

追答

你厉害,
- - 那就算我没有回答这个题吧。

参考技术B 虚函数是为了实现动态函数调用的
class A

virtual printf() cout<<"A";
;

class B:public A

virtual printf() cout<<"B";


class C:public A

virtual printf() cout<<"C";


int main()

A *b1=new B();

A *c1=new C();

b1->printf();
c1->printf();
//你觉得会输出什么结果

追问

我知道虚函数有什么用。

但是你要调用子类父类爷类函数用的着这样么?

直接创建子类对象。然后对象名::作用域 函数名

搞定了,你想调用哪个就调用哪个,搞个虚函数干什么

虚函数本质

虚函数本质就是一个函数指针

友元函数不能声明为虚函数,但是虚函数可以作为另一个类的友元。

 

构造函数不可以是虚函数,若声明为虚函数:不会再次构造,没有办法创建子类中父类对象

 

虚析构函数,让父类指针正确的释放子类对象的内存:先调用子类的析构,再调用父类的析构

 

纯虚函数

含有纯虚函数的类为抽象类,抽象类是不可以实例化对象的,可以定义指针,提供同一个接口以完成不同功能;

抽象类不可以作为函数的返回值和参数,抽象类指针可以。可以实现适配器模式

把所有接口都实现了才可以实例化,只要有一个接口没有实现就是抽象类

 

不管一个类中含有多少个虚函数,都只占4个字节,一个指针存储了虚函数表的地址

 

以上是关于为何需要虚函数 直接对象名加作用域来调用子类父类爷类的函数不就行了 为啥的主要内容,如果未能解决你的问题,请参考以下文章

请教,父类中如何调用子类中的虚函数

C++的构造函数为何不能为虚函数

vc 父类实现一个虚函数,子类继承并也实现这个虚函数,子类调用这个虚函数,父类这个虚函数会不会执行?

面向对象:继承抽象类抽象方法虚方法

c++ 虚函数 如何调父类 而非子类

父类子类指针相互转换问题