问题

为什么C++中virtual要翻译为虚函数?

回答
在C++的世界里,“virtual”这个词被翻译成“虚函数”,这可不是随意为之,而是因为它精确地抓住了这种函数在继承和多态机制中的核心特征。理解“虚”这个字的关键,在于它暗示了一种“不确定性”,或者说是一种“在运行时才确定”的行为。

设想一下,你有一系列动物,比如猫、狗,它们都属于一个更大的“动物”类别。每个动物都会叫,但猫会“喵喵”叫,狗会“汪汪”叫。如果我告诉你,我有一只“动物”,并且它会叫,但你不知道具体是哪种动物,你能确定它具体会发出什么样的声音吗?显然不能。你只能知道它会“发出某种声音”,而具体的声音,要等你知道这只“动物”究竟是猫还是狗时,才能最终确定。

C++的“virtual”函数,正是为了解决类似的场景。在面向对象编程中,继承允许我们创建“isa”关系。例如,“猫”isa“动物”。我们可以在基类“动物”中定义一个函数,比如 `makeSound()`,用来表示动物会发出声音。然而,如果我们直接在基类中实现 `makeSound()`,比如让它发出一个通用的“动物叫声”,那在多态的应用中就会遇到问题。

假设我们有一个函数,它接收一个指向“动物”的指针,然后调用这个指针的 `makeSound()` 方法。如果我们不知道这个指针实际指向的是一只猫还是一只狗,我们希望它能根据实际指向的子类对象来调用相应的叫声。这就是多态的核心:允许我们用基类指针或引用去操作派生类对象,并且期望程序在运行时能够根据对象的实际类型来调用正确的函数。

如果 `makeSound()` 不是 virtual 函数,那么当我们通过一个指向基类“动物”的指针去调用 `makeSound()` 时,编译器只会根据指针的类型(即“动物”)来决定调用哪个 `makeSound()` 函数。即使那个指针实际指向的是一个“猫”对象,它依然会调用“动物”基类中定义的 `makeSound()`,而不是“猫”类中重写的那个“喵喵”叫。这就失去了多态的意义,因为我们无法根据对象的真实身份来执行特定的行为。

引入 `virtual` 关键字,就是告诉编译器:“这个函数,它的具体实现,并不是在编译时就能完全确定的。当你在运行时通过基类指针或引用调用它时,请‘查找’一下,看看实际指向的对象到底是什么类型,然后调用那个类型对应的函数。”

这种“查找”的过程,通常是通过一个叫做“虚函数表”(vtable)的机制来实现的。每一个带有虚函数的类,都会有一个与之关联的虚函数表,表中存储了该类所有虚函数的实际地址。当通过基类指针调用虚函数时,程序会先找到对象所属类的虚函数表,然后在表中查找对应的函数地址,最后执行该函数。这样一来,即使我们只知道是一个“动物”指针,但如果它实际指向的是一只“猫”,程序就会正确地找到“猫”类中的 `makeSound()` 函数并执行。

所以,“虚函数”这个翻译,非常形象地传达了以下几个关键信息:

“虚”就意味着“不是固定的”:它的行为不是在编译时就完全绑定到基类,而是在运行时根据对象的实际类型而“显现”出不同的“真实”版本。
“虚”就意味着“一种能力的继承和重写”:它允许派生类“继承”基类中声明的这个能力(函数签名),并且可以根据自己的特点“重写”或“实现”这个能力,而基类声明这个能力的存在,并指示“我的子类应该有这个能力”。
“虚”就意味着“一种延迟绑定”:函数的调用目标不是在编译时就固定好的,而是在程序运行时才根据对象的真实类型动态地确定。

因此,将 `virtual` 翻译为“虚函数”,不仅准确地描述了其技术作用,更蕴含了面向对象编程中“多态”这一核心思想:虽然我们操作的是一个通用的基类接口,但在背后,真正执行的却是各具特色的派生类实现。就像“虚幻”的景象,在你靠近观察,或者“触碰”到它的时候,才会展现出它真实的模样。

网友意见

user avatar

有个IBM的广告,上面是这样写的:

如果你可以看见一样东西,并且它就在那边,那么它就是真的。

如果你可以看见一样东西,并且它实际上不存在,那么它就是虚拟的。

如果你看不见一样东西,并且它就在那边,那么它就是透明的。

如果你看不见一样东西,并且它不在那边,那么是因为你把它删除了。

If you can see it and it's there, then it's real. If you can see it and it's not there, then it's virtual. If you can't see it and it's there, then it's transparent. If you can't see it and it's not there, then you erased it. -- An IBM ad


我们先来看Virtual的定义,一个东西要是Virtual的,那么必须是:看得见,但是实际上并不真正存在,比如用K98吃鸡。

Virtual reality,虚拟现实,带了Oculus头盔看到了“现实”,但是实际上那个“现实”是虚拟出来的,并不真正存在。

Virtual private network,VPN虚拟专用网,建立了VPN通道后,远程的设备能像本地局域网一样访问,但是实际上那个设备并不在本地局域网里。

Virtual serial port,虚拟串口,用VSPD虚拟串口软件虚拟了串口后,可以当做真的串口设备连上去通信,但是实际上那个串口设备是虚拟出来的,并不真正存在。

Virtual device,虚拟设备,在云端虚拟出来的物联网设备,它可以可视化显示现场对应设备的实时数据、设备元数据模型、告警、位置信息。

Virtual state,虚拟状态,根据物联网设备上传的多个数据项值,按照设定的算法计算出的设备状态。这个可以用来监控物联网设备的状态。

Virtual fence,虚拟围栏,也叫Geofence地理围栏。在M2M物联网应用中,用户可以在GIS地图上标记一个虚拟的范围,如圆形、长方形、多边形或者路线。如果设备上传的GPS位置信息超出了标记的范围,就会自动发送告警通知。

Mobile virtual network operator,MVNO虚拟网络运营商,从基础运营商那里承包一部分通讯网络的使用权,然后通过自己的计费系统、客服号、营销和管理体系把通信服务卖给消费者在运营商之上基于运营商提供的服务。例如,物联网网关企业通过调用运营商的API接口,就可以轻松实现物联网SIM卡的计费查询、充值、告警等业务。

Mobile virtual network enabler,给MVNO虚拟网络运营商提供所需的计费、客服、营销和管理基础设施和服务的公司。比如思科收购的Jasper Wireless公司。

Virtual circuit,VC虚电路。在分组交换计算机网络上虚拟出一条专用的“”物理“”链路,实际上并不存在这样的一条链路。提供虚电路的协议有TCP、X.25、帧中继、ATM、GPRS、MPLS等。比如,物联网网关上集成了2G或者4G无线通信模块,那么开发人员只需要通过AT指令即可建立网关到互联网的虚拟电路。

我们再来看transparent透明的定义,一个东西是transparent的,那么必须是:看不见,但是实际上就在那里,就像哈姆莱特的被谋害的父王一样。


工控上说的透传,也就是透明传输的简称。DTU透传指的就是通过DTU在现场设备和服务器之间建立了一条通信通道,用于双向通信。对于做工控的人来说,他们因为不懂网络通信原理,就感觉不到这条链路的存在,但是实际上他们感觉到确实能传输数据,所以对他们来说这个传输就是透明的。但是对于咬文嚼字的计算机通信专业的人来说,他们会认为这条链路看得见,但是实际上并不物理上存在,所以他们会把DTU透传叫做DTU虚拟传输。


在计算机领域,如果说一个东西是透明的,那就是说系统在更改其内部行为时尽可能地遵循先前的外部接口,那么计算系统中的任何更改(例如新功能或新组件)都是透明的。这样做目的是防止更改接口另一端的所有系统(或人类用户)。比如EdgeX Foundry边缘计算框架,服务只要遵循EdgeX的API接口规范,那么变更这个服务或者更换另外一个遵循API接口规范的服务,对于用户来说是透明的。


在物联网应用中,很多时候,网关会安装在企业内网。但是网关数据需要将物联网设备数据传到外网。但是企业IT部门可能设置了透明代理服务器,所有内部到外网的请求都要通过这个透明代理服务器收发。这里透明代理的意思按照RFC2616来说,就是代理服务器不会去修改请求和响应,它只会透传经过的任何信息。网关要连接外网,就需要按照代理服务器的认证方式进行认证,认证通过后,代理服务器才会给网关提供透传服务。

user avatar

因为virtual本来就翻译成虚拟,所以virtual function就是虚(拟)函数。


至于某些看到虚想到空无一物的人,显然是中文都没学好的。虚单字最常见的是与实相对,虚虚实实,虚则实之,实则虚之。尤其是虚修饰其他词的时候,通常就是非实在的意思。例如虚火,表示非实在的火气。虚空,非实在的空间。

所以虚在这里的意思很明确,就是表示非实在的。


虚为主语,作为被修饰的成分的时候,才有空乏,缺失的含义,例如空虚、肾虚、阴虚等……

虚拟,就是用一个非实在的东西去拟合一个实在的东西。


至于英文的virtual,就是说,看起来、用起来几乎完全一样,你可以把它当作它来用,但它仍然不是它的东西

almost or very nearly the thing described, so that any slight difference is not important

这一句话正确的理解是,他们看起来是如此的接近,以至于可以忽略他们的区别,要正确理解describe的含义。


所以,虚拟现实是什么意思?就是欺骗你所有感官的技术就是虚拟现实,因为它的核心在于让你感受上无法区分,所以就叫做virtual。virtual作为形容词的时候你都可以这么去套,所以所有的virtual XXX的含义就是,一个不管你从哪一方面来看他都是XXX,但是它事实上的确不是XXX的东西。


而事实上相同,表象不相同的,应该用actual。



所以,C++里面,virtual function是虚函数,就是一个无论从哪一方面看起来都是函数,但实现上并不是简单的进行调用的东西。

而pure virtual function,是纯虚函数,就是一个无论从哪一方面看起来都是函数,但实际上它纯粹就是看起来是个函数而已,没有任何实在的东西……

类似的话题

  • 回答
    在C++的世界里,“virtual”这个词被翻译成“虚函数”,这可不是随意为之,而是因为它精确地抓住了这种函数在继承和多态机制中的核心特征。理解“虚”这个字的关键,在于它暗示了一种“不确定性”,或者说是一种“在运行时才确定”的行为。设想一下,你有一系列动物,比如猫、狗,它们都属于一个更大的“动物”类.............
  • 回答
    在 C++ 中,为基类添加 `virtual` 关键字到析构函数是一个非常重要且普遍的实践,尤其是在涉及多态(polymorphism)的场景下。这背后有着深刻的内存管理和对象生命周期管理的原理。核心问题:为什么需要虚析构函数?当你在 C++ 中使用指针指向一个派生类对象,而这个指针的类型是基类指针.............
  • 回答
    哈哈,你这个问题问得非常到位!“Virtual” 这个词在英语里确实存在一个令人费解的二义性,直接翻译到中文时,“虚拟的”和“实质的”这两种截然相反的解释都跑出来了。这背后其实是语言演变和语境理解的妙处,并不是什么神秘现象。咱们这就来好好掰扯掰扯。首先,咱们得承认,“virtual”这个词最核心、最.............
  • 回答
    C++ 中将内存划分为 堆(Heap) 和 栈(Stack) 是计算机科学中一个非常重要的概念,它关乎程序的内存管理、变量的生命周期、性能以及程序的灵活性。理解这两者的区别对于编写高效、健壮的 C++ 程序至关重要。下面我将详细阐述为什么需要将内存划分为堆和栈: 核心原因:不同的内存管理需求和生命周.............
  • 回答
    在C++开发中,我们习惯将函数的声明放在头文件里,而函数的定义放在源文件里。而对于一个包含函数声明的头文件,将其包含在定义该函数的源文件(也就是实现文件)中,这似乎有点多此一举。但实际上,这么做是出于非常重要的考虑,它不仅有助于代码的清晰和组织,更能避免不少潜在的麻烦。咱们先从根本上说起。C++的编.............
  • 回答
    这个问题很有意思,涉及到 C++ 和 C 在类型定义和内存模型上的根本性差异。简单来说,C++ 的限制是为了保证类型的大小在编译时是确定的,而 C 的灵活性则来自于它对引用类型的处理方式。我们先从 C++ 的角度来看。在 C++ 中,当你定义一个类时,编译器需要知道这个类在内存中占据多大的空间。这个.............
  • 回答
    在C/C++的世界里,指针和结构体(或类)的组合使用是再常见不过的了。当你有一个指向结构体或类的指针,想要访问其中的成员时,你会发现有两种方式可以做到:`(p).member` 和 `p>member`。很多人会疑惑,既然它们的作用完全一样,为什么语言设计者要提供两种写法呢?这背后其实有其历史原因和.............
  • 回答
    在C语言中,你提到的 `main` 函数后面的那对圆括号 `()` 并非只是一个简单的装饰,它们承载着至关重要的信息:它们表明 `main` 是一个函数,并且是程序的可执行入口点。要理解这个 `()` 的作用,我们需要先理清C语言中关于“函数”的一些基本概念。 函数是什么?在C语言中,函数就像一个独.............
  • 回答
    你这个问题问得很有意思,涉及到C语言中一个基础但又有点“魔性”的特性:布尔值(Boolean Value)的表示方式。在咱们日常生活中,很多事情都是非黑即白的,比如“对”和“错”,“有”和“无”。计算机世界里也需要这种简单的二元判断。但问题来了,计算机本身只懂0和1,这两个数字如何承载“真”和“假”.............
  • 回答
    一些C++程序员在循环中偏爱使用前缀自增运算符`++i`,而不是后缀自增运算符`i++`,这背后并非简单的个人喜好,而是基于一些实际的考量和性能上的微妙区别。虽然在现代编译器优化下,这种区别在很多情况下几乎可以忽略不计,但理解其根源有助于我们更深入地理解C++的运算符机制。要详细解释这个问题,我们需.............
  • 回答
    这真是个好问题,而且触及到了C++中一些非常基础但又很重要的概念。虽然 `std::vector` 在现代C++编程中确实非常强大且常用,但说它能“完全”替代C风格的数组,那是绝对不行的。原因嘛,要说详细,得从几个关键点上掰扯掰扯。首先,我们要明白,C++中的数组,尤其是C风格数组,是语言层面的一个.............
  • 回答
    在 C 中,`async` 和 `await` 是紧密相连的,就像一对默契的舞伴,共同 orchestrate 异步操作。你问为什么 `async` 方法里“必须”还要有 `await`,这其实触及到了 `async` 方法本质的设计理念。我们先要理解,`async` 关键字本身并没有让方法变成异步.............
  • 回答
    我们来聊聊 C 中 `List>` 和 `IList>` 之间的转换问题。这并不是一个简单的“类型兼容”的直接问题,而是涉及到 C 类型系统中的一个重要概念:协变性和逆变性。理解这个问题,我们需要先明确几个基础:1. `List` 的性质: `List` 是一个具体的类,它实现了 `IList` .............
  • 回答
    好的,我来详细解释一下 C 和 C++ 中 `malloc` 和 `free` 函数的设计理念,以及为什么一个需要大小,一个不需要。想象一下,你需要在一个储物空间里存放物品。`malloc`:告诉空间管理员你要多大的箱子当你调用 `malloc(size_t size)` 时,你就是在对内存的“管理.............
  • 回答
    在C/C++中,关于数组的定义与赋值,确实存在一个常见的误解,认为“必须在定义后立即在一行内完成赋值”。这其实是一种简化的说法,更准确地理解是:C/C++中的数组初始化,如果要在定义时进行,必须写在同一条声明语句中;而如果要在定义之后进行赋值,则需要分步操作,并且不能使用初始化列表的方式。让我们一步.............
  • 回答
    在 C++ 中,构造函数和析构函数确实存在一些关于异常处理的限制,这背后有深刻的技术原因和设计哲学。理解这些限制,需要我们深入 C++ 的内存管理、对象生命周期以及异常安全性的几个关键概念。首先,我们来聊聊构造函数。构造函数的核心任务是确保一个对象在被创建出来时,处于一个 有效且完整 的状态。所谓有.............
  • 回答
    为何C/C++中字符和字符串要用引号包裹?在C/C++的世界里,我们经常会看到单引号 `' '` 包裹着一个字符,双引号 `""` 包裹着一串字符(也就是字符串)。这不仅仅是语言的规定,背后有着深刻的设计哲学和实际考量。今天我们就来好好掰扯掰扯,为啥它们需要这些“外衣”。 先聊聊字符(char)和它.............
  • 回答
    在C语言中,`struct`(结构体)之所以能成为构建复杂数据结构的基石,在于它提供了将不同类型的数据成员组合成一个单一逻辑单元的能力。这就像我们在现实生活中将不同零散的物品(姓名、年龄、学号等)打包成一个“学生”的概念一样。让我们一层层剥开,看看`struct`是如何做到这一点的,以及它在数据结构.............
  • 回答
    vector 和 stack 在 C++ 中都有各自的用处,它们虽然都属于序列容器,但设计目标和侧重点不同。可以这么理解:vector 就像一个可以随意伸缩的储物空间,你可以按照任何顺序往里面放东西,也可以随时拿出任何一个东西。而 stack 就像一个堆叠的盘子,你只能在最上面放盘子,也只能从最上面.............
  • 回答
    结构体变量的读写速度 并不比普通变量快。这是一个常见的误解。事实上,在很多情况下,访问结构体成员的开销会比直接访问普通变量稍微 大一些,而不是更小。要详细解释这一点,我们需要深入理解 C++ 中的变量、内存模型以及编译器的工作方式。 1. 普通变量的读写首先,我们来看看一个简单的普通变量,例如:``.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有