C++的虚函数,动态(运行期)多态性是不是一个多此一举的不必要的设计?

renxu350 2010-10-16 12:05:03
1. C++的设计者为什么要设计运行期多态性?既然"对象.类::成员函数()"这个形式能解决问题,C++的设计者为什么要设计一个多此一举的运行期多态性?

2. 运行期多态性似乎是一种“假动态”,众所周知,非虚函数的调用指令,在程序被编译链接后,其调用指令包含一个链接器链接的“常量”地址,该“常量”地址就是此非虚函数的静态地址,这是所谓的静态的编译期的多态性,而动态的运行期多态性就真的是动态的吗?所谓的运行期多态性,无非就是在类的对象被构造时,编译链接器,或者装载器为对象构造一个虚函数表指针成员变量,此指针成员变量对外不可访问,此指针指向此对象的类族的虚函数表,而虚函数表中的一个个的虚函数实质上还是一个个静态的地址,只不过是通过一个中间指针,间接的调用,这样就变成动态的?这是一种假动态?

3. 在实际的社会生产生活应用中,有没有什么实际的例子,实际的问题,必须不得不由虚函数出马来解决才能完成,而"对象.类::成员函数()"这样的形式是完成不了的实际的问题呢?大家有没有遇到过这样的问题呢?
...全文
581 53 打赏 收藏 转发到动态 举报
写回复
用AI写文章
53 条回复
切换为时间正序
请发表友善的回复…
发表回复
bluejays 2010-10-18
  • 打赏
  • 举报
回复
[Quote=引用 42 楼 renxu350 的回复:]
“但是就得判断是哪个派生类然后调用对应的draw,这样就很累。”
对比方法1,方法2,“很累”的似乎还是动态多态性的调用方法?
因为每次调用之前,基类的指针还要重新指一次?
从算法效率的角度而言,这不是增加了语句,降低了效率了吗?
[/Quote]
算法效率可能是低一点,但是开发效率要高很多。
这个要折衷一下,要是全都追求算法效率,大家也不用玩java了
hastings 2010-10-16
  • 打赏
  • 举报
回复
iostream可能就是一个很神奇的东西吧~~
ForestDB 2010-10-16
  • 打赏
  • 举报
回复
再看看理论吧,比如“编程语言设计原理”,“C++演化”之类的;
还有就是了解下其它语言,有对比才有理解。
科技完美生活 2010-10-16
  • 打赏
  • 举报
回复
额的神啊,没有虚函数怎么玩多态,没有多态那C++不就成C了么,玩的就是多态
renzhewh 2010-10-16
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 hikaliv 的回复:]
目前的 C++ 又不是动态语言,哪里可能来所谓的“动态”多态去。运行时多态,不是运行时动态多态,不要搞混了。C++ 的运行时多态是静态运行时多态,也就是编译期绑定的多态,楼主你说对了,就是这么一回事儿。不过这个也是多态啊。运行时动态多态是需要反射的。目前C++ 还没有反射,所以是不可能存在动态多态的。
[/Quote]

C++通过泛型可以提供一个新的类型检查模型,等效于动态类型语言

回34#
泛型编程只是oo的一种方式而已
neu_yanggx 2010-10-16
  • 打赏
  • 举报
回复
很牛X的设计

面向对象的思想的一部分
bluejays 2010-10-16
  • 打赏
  • 举报
回复
举个教科书上的例子:
有个类叫Shape,成员函数draw(),有很多派生类Circle、Triangle等等。每个形状的画法都不一样。如果用虚函数,上层的代码直接调用draw即可,不必关心具体是哪个派生类。以后增加了新的派生类,上层的代码也不用改。如果不用虚函数,当然也可以解决问题,但是就得判断是哪个派生类然后调用对应的draw,这样就很累。
bluejays 2010-10-16
  • 打赏
  • 举报
回复
1. 运行期多态不是多此一举,很多时候都有用,很方便。
2. 真假无所谓,达到目的就好。
3. LZ说的“不得不”例子还真不一定有。即使彻底不用类,就用c来硬写,我想大多数问题也是能解决的吧,不过开发周期、效率、可维护性就会差很多。
cswuyg 2010-10-16
  • 打赏
  • 举报
回复
楼主看过多态的例子吗???
"对象.类::成员函数()"这个形式能解决问题????
要是能这样写,就不叫多态了。
昵称很不好取 2010-10-16
  • 打赏
  • 举报
回复
多态是面向对象的特征,编译时期就已经决定的还能算多态吗?
war10811 2010-10-16
  • 打赏
  • 举报
回复
面向对象,封装继承多态,不是为解决项目的逻辑问题而产生的,,而是能让项目能更好的扩展,维护和修改
yangyunzhao 2010-10-16
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 renzhewh 的回复:]
引用 19 楼 schoolers 的回复:
多态是面向对象的特征,编译时期就已经决定的还能算多态吗?


多态分为编译期多态,由模板实现,另一种是运行期多态,由虚函数实现
[/Quote]
前者是泛型编程,后者是面向对象
光宇广贞 2010-10-16
  • 打赏
  • 举报
回复
最后,C++ 根本没有什么“运行时”的概念。程序员和编译器都无法干预C++程序的运行时。讨论C++运行时本身就是错误。还有楼上讨论C++模板的。模板也是静态绑定。否则C++也不会有模板元编程这么一个玩意儿。C#一类的OOP有泛型,泛型是动态绑定的,也就是运行时,因为它可能会出现运行时生产的问题,编译期无法推导绑定。C++ 不具备这个特点,或者干脆说,其实C++根本不允许有这种情况的出现。

既然C++不允许,那还有什么运行时这个那个的问题?C++拒绝讨论这类的问题。

至于“对像.*&类::函数()”,正确的写法儿应该是这个。它和多态有什么关系?多态用的是虚地址表。你这个可是通过指针把地址写实了。这叫人为干预,可能会出现极其严重的问题。它告诉你C++完全可以这么玩儿,也告诉了你C++里面类对像内部调用方法的本质。这些本该是编译器帮你完成和检查的。如果你是一个比编译器还牛X的程序员,玩儿玩儿倒也无所谓。
zrebecca 2010-10-16
  • 打赏
  • 举报
回复
这个不是多此一举,而是一个很好的设计
光宇广贞 2010-10-16
  • 打赏
  • 举报
回复
还有,多态不是“假动态”,多态和动态根本不是一回事儿,多态和动态根本没有什么关系。放在一起比搞混逻辑和概念让人糊涂本身就是错误。

知道什么叫做“动态”么?运行时的生产与消费才是动态。多态指的是虚继承。C++ 具备动态么?不,C++ 没有反射,没有动态。我看楼上很多人也都被这个混乱给搞糊涂了。

对于有反射机制的 OOP 语言,也可以出现动态多态,那就是在运行时生成虚继承关系。本不相干的两个概念。C++ 无法动态,那就静态绑定虚继承关系,又有什么问题?动静态与是否多态有什么冲突?
光宇广贞 2010-10-16
  • 打赏
  • 举报
回复
目前的 C++ 又不是动态语言,哪里可能来所谓的“动态”多态去。运行时多态,不是运行时动态多态,不要搞混了。C++ 的运行时多态是静态运行时多态,也就是编译期绑定的多态,楼主你说对了,就是这么一回事儿。不过这个也是多态啊。运行时动态多态是需要反射的。目前C++ 还没有反射,所以是不可能存在动态多态的。
shuiyu 2010-10-16
  • 打赏
  • 举报
回复
多态是面向对象最重要的概念之一
面向对象解决了过去结构化程序设计中的一些问题,其中多态是最重要的手段

举个例子,来自《设计模式精解》,大致是说:
大学生上课,一堂课完成了,学生们去另外一间课室上下一节课。传统的结构化设计,可能是由教授,遍历每一个学生,告诉他下节课是什么,在哪个课室,怎么走。
这时如果增加一个新需求,有一种学生叫“班长”,去上下节课之前先要到班主任那里一下,“教授”的逻辑就要进行相应修改,if是班长,则执行另外一套流程

而面向对象的设计认为,对象应该对自己的行为负责(也叫做“单一职责原理”),每个学生负责自己从一个课室到下一个课室的行为,教授只负责告诉他们,“这节课完了,去上下一节课吧”。
如果要增加“班长”,“班长”是“学生”的一种派生,是去班主任那里还是去辅导员那里是班长自己的事情,教授不必知道

这里,“去上下一节课”就是一个“学生”的虚函数,“班长”继承并改写其中的逻辑。而教授只需要知道“学生”都有“去上下节课”这个虚函数即可,不必关心这个学生是否是“班长”
这就是多态的作用,降低了对象间的耦合


至于动态不动态,我理解只要不是编译期能确定的,就叫动态吧
17楼的例子,稍微改一点,是不是会更“动态”一点

Base* fun()
{
cout << "input type: ";
int t;
cin >> t;
switch (t) {
case 0:
return new Base;
case 1:
return new Drived;
default:
return NULL;
}



至于C++的虚函数表,只是多态的一种实现方式。
另外一些语言,例如smalltalk是为每一个类记录改写了哪些函数。调用时根据继承树倒过来查找。效率要低一些,但是节省空间。MFC的消息映射机制,也可以理解为是一种多态,就是这种方式实现的
shuiyu 2010-10-16
  • 打赏
  • 举报
回复
多态是面向对象最重要的概念之一
面向对象解决了过去结构化程序设计中的一些问题,其中多态是最重要的手段

举个例子,来自《设计模式精解》,大致是说:
大学生上课,一堂课完成了,学生们去另外一间课室上下一节课。传统的结构化设计,可能是由教授,遍历每一个学生,告诉他下节课是什么,在哪个课室,怎么走。
这时如果增加一个新需求,有一种学生叫“班长”,去上下节课之前先要到班主任那里一下,“教授”的逻辑就要进行相应修改,if是班长,则执行另外一套流程

而面向对象的设计认为,对象应该对自己的行为负责(也叫做“单一职责原理”),每个学生负责自己从一个课室到下一个课室的行为,教授只负责告诉他们,“这节课完了,去上下一节课吧”。
如果要增加“班长”,“班长”是“学生”的一种派生,是去班主任那里还是去辅导员那里是班长自己的事情,教授不必知道

这里,“去上下一节课”就是一个“学生”的虚函数,“班长”继承并改写其中的逻辑。而教授只需要知道“学生”都有“去上下节课”这个虚函数即可,不必关心这个学生是否是“班长”
这就是多态的作用,降低了对象间的耦合


至于动态不动态,我理解只要不是编译期能确定的,就叫动态吧
17楼的例子,稍微改一点,是不是会更“动态”一点

Base* fun()
{
cout << "input type: ";
int t;
cin >> t;
switch (t) {
case 0:
return new Base;
case 1:
return new Drived;
default:
return NULL;
}



至于C++的虚函数表,只是多态的一种实现方式。
另外一些语言,例如smalltalk是为每一个类记录改写了哪些函数。调用时根据继承树倒过来查找。效率要低一些,但是节省空间。MFC的消息映射机制,也可以理解为是一种多态,就是这种方式实现的
shuiyu 2010-10-16
  • 打赏
  • 举报
回复
多态是面向对象最重要的概念之一
面向对象解决了过去结构化程序设计中的一些问题,其中多态是最重要的手段

举个例子,来自《设计模式精解》,大致是说:
大学生上课,一堂课完成了,学生们去另外一间课室上下一节课。传统的结构化设计,可能是由教授,遍历每一个学生,告诉他下节课是什么,在哪个课室,怎么走。
这时如果增加一个新需求,有一种学生叫“班长”,去上下节课之前先要到班主任那里一下,“教授”的逻辑就要进行相应修改,if是班长,则执行另外一套流程

而面向对象的设计认为,对象应该对自己的行为负责(也叫做“单一职责原理”),每个学生负责自己从一个课室到下一个课室的行为,教授只负责告诉他们,“这节课完了,去上下一节课吧”。
如果要增加“班长”,“班长”是“学生”的一种派生,是去班主任那里还是去辅导员那里是班长自己的事情,教授不必知道

这里,“去上下一节课”就是一个“学生”的虚函数,“班长”继承并改写其中的逻辑。而教授只需要知道“学生”都有“去上下节课”这个虚函数即可,不必关心这个学生是否是“班长”
这就是多态的作用,降低了对象间的耦合


至于动态不动态,我理解只要不是编译期能确定的,就叫动态吧
17楼的例子,稍微改一点,是不是会更“动态”一点

Base* fun()
{
cout << "input type: ";
int t;
cin >> t;
switch (t) {
case 0:
return new Base;
case 1:
return new Drived;
default:
return NULL;
}



至于C++的虚函数表,只是多态的一种实现方式。
另外一些语言,例如smalltalk是为每一个类记录改写了哪些函数。调用时根据继承树倒过来查找。效率要低一些,但是节省空间。MFC的消息映射机制,也可以理解为是一种多态,就是这种方式实现的
renzhewh 2010-10-16
  • 打赏
  • 举报
回复
至于多态是否是动态的,lz 认为什么样的代码可以称之为动态呢
我一直不解,曾经在《代码之美》中看到“即时编码技术”,不知道这是否算是动态的呢?
加载更多回复(33)

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧