读书人

为什么说C++落伍了?该如何处理

发布时间: 2012-02-11 09:51:35 作者: rapoo

为什么说C++落伍了?
前一段时间,在C++版的几个帖子里参与了一点讨论。也许某些观点触痛了几个C++爱好者的神经,被指责为“不懂装懂”、“没有建设性”、“踢场子”。
我当然不是大师,也不是牛人,不过相比某些满嘴跑火车,夸夸其谈没有来路的“OO规则”、什么“黑盒OO”、“白盒OO”的“神人”(比大师还牛,一开口就能“自主创新”),自信还是要懂那么一点点。
既然有人要我“拿出证据”,我也必须对自己的言论负责,就再装一回懂,谈谈“为什么C++落伍了”。
我的意思当然是讨论了,不过某些人非要说我“踢场子”,就当是踢场子吧。

先说一点,我并没有贬低C++,C++有很多优点,诸如语言能力比较强,实现平台多,有很多免费的工具和库可用等等,我在另一个帖子里也说了“C++是3GL的集大成者”。我针对的只是“C++就是好,就是好来就是好”、“全面优于其他语言”、“综合能力优于其他语言”(这种观点还算可以讨论)。

C++的一些缺点,诸如学习曲线的问题,缺少标准的应用框架(GUI、线程库、GC)等等,已经说得太多了,连BS这样的“C++之父”都说了(当然他是有一些辩解的)。
我就象某人那样“只谈技术”、“只谈语言本身”。

1. C++对象模型问题
准确地讲,是C++的对象存储模型。
C++的对象存储,使用一种简单模型,也就是对象(对象是类的实例)直接代表一个存储区域,存储它的内部成员。这种结构当然有它的优点:占用存储空间比较少,对象的创建和销毁比较简单也比较快(针对基于栈的,基于堆的对象在C++中要显式使用一个指向对象的指针,更加复杂)。
// 这些特征让我们想起它产生的时代背景:计算机比较慢、内存比较少。
但是这种结构也有明显的问题:
a. 为了实现多态,需要引入指针或引用。
b. 子类兼容也需要引入指针或引用。
c. 默认是基于栈的,而对象占用的空间较多(相比简单类型),潜在的导致栈溢出的可能性更大一些。
d. 对象的赋值是拷贝,这经常导致代码的性能问题(要解决就要显式使用指针)。
e. 这种存储结构有被利用进行缓冲区溢出攻击的潜在可能。

前面几个都是常识了,讲解C++的书多少都会提及,只多说一下e问题。
由于C++的对象直接映射到一个实际存储空间,利用缓冲区溢出篡改对象的内部数据结构从而改变程序流程的可能性要比使用引用模型的语言大。
比如如下程序:

#include <iostream>
#include <string.h>

using namespace std;

class bot
{
private:
char password[8];
public:
bot(){strcpy(password, "abc ");};
virtual ~bot(){};
bool checkpwd(const char *pwd){return (!strcmp(password, pwd));};
};

char s[8];
bot b;

int main()
{
for(;;)
{
cout < < "Enter password: ";
cin > > s;

if (b.checkpwd(s))
{
cout < < "Access permitted.\n\n ";
break;
}
else
cout < < "Access denied.\n\n ";
}
return 0;
}

密码是abc,正常情况下不输入abc是不可能通过的。
但是我们输入123456789012123试试,还是不行。
我们再输入123,居然通过了。
原因就是我们输入123456789012123的时候造成了缓冲区溢出,把b的内部数据password覆盖了,改成了123,这样再次输入123的时候就通过了。
(注:
(1). bcc32 5.82(BCB 2006)和cl 13.10.3077(VC++ 7.1)编译通过,其他编译器未测试。
(2). 之所以需要12个字节才覆盖到b是数据对齐的原因。
(3). 这个例子只是用来说明C++的对象模型可能导致缓冲区溢出攻击的原因,凡是批评程序结构不当、风格有问题的免开尊口。


这个例子是基于静态数据区的。基于栈分配,仍然可能构成攻击条件,尽管某些编译器(比如VC++ 7.1),在编译时有意调整局部变量的顺序,把char[]之类的缓冲区排在高地址而避免潜在的风险。但是这种避免只是在一个函数内部,不同函数中的局部变量编译器就无法调整了,所以一个函数内部的缓冲区还是可能溢出到直接或者间接调用它的函数在栈上创建的对象(当然形成攻击要更困难一些,因为覆盖了函数的返回地址)。

在基于引用的对象模型中,声明一个对象只是创建一个引用(本质上是指针),对象的实际存储空间是在堆上动态创建的,形成这种缓冲区溢出攻击的条件要困难得多。而在栈上的这种缓冲区溢出攻击,对基于引用的对象模型彻底无效,因为你再溢出也只能在栈段内部,无法篡改堆上的对象存储空间。

客观地说,C++的对象模型是80年代的产物(1989年的Turbo Pascal 5.5就使用与C++类似的对象模型,Delphi中仍然兼容支持这种object类型,但是标明“不推荐使用”)。
它无法隐藏指针和引用,在语法上不完美,在结构上有严重问题(允许在OO结构中暴露指针,这已经破坏了OO的三大特征之一---封装),而且容易被利用进行缓冲区溢出攻击。
90年代以来的OOPL,毫无例外地都使用引用模型,没有使用类似C++的模型的(也许我孤陋寡闻了,但至少象C#、Delphi、Java这些使用比较广泛的语言都是如此)。
这只能证明C++的对象模型过时了,总不可能C++的设计者最高明,其他语言的设计者都很蠢吧(可能性有多大呢?应该比你买彩票中大奖的可能性要小)。
而一个基本对象模型都过时了的语言,称之为“落伍”不算夸张吧。:)

(待续,明天接着写,没时间就是后天)


[解决办法]
沙发
不是你说落伍就落伍了的
[解决办法]
这个题目就没有什么建设性..C++ 落伍??? 连BASIC和ASM都没落伍怎么沦到C++了,汗


[解决办法]
落伍怎么了,能找到好工作能赚到钱的我管它落不落伍
[解决办法]
管他落伍不落伍,能养活我就成
[解决办法]
mark
[解决办法]
前十。
[解决办法]
偶用更落后的C, 友情帮顶 ...
[解决办法]
这只能证明C++的对象模型过时了,总不可能C++的设计者最高明,其他语言的设计者都很蠢吧(可能性有多大呢?应该比你买彩票中大奖的可能性要小)。

///////////////////////////////////////////////////////////////////////////

这些都只能证明C/CPP不是设计来给你这样的Coder用的(此处无褒贬)。

我总觉的C/CPP差不多可以说是世界上最容易掌握的语言之一。某种意义上说是最简单的语言之一。因为当C/CPP把几乎一切都暴露给你的时候。你也同时拥有了最大的选择范围和权力。换句话说,C/CPP期待和信任你会并且能做出正确的决定,也给了你作出正确决定的机会。that 's all

所以抱怨指针如何如何,或者堆上OR栈上,或者深浅拷贝之类是没有什么意思的。C/CPP永远认为它没有你聪明。所以它很聪明的让“聪明些的家伙们”来做决定。

C/CPP本质上是对冯诺体系的比较低lvl(所以高效)的抽象,除非冯诺体系出现了很大的变化。否则C/CPP会一直存在并流行下去。
[解决办法]
好像没有那款OS不是C/C++/ASM写的
[解决办法]
关注讨论...
[解决办法]
矛和盾的问题.
[解决办法]
放着安全、方便的string不用,却去用数组,还说什么溢出。溢什么出啊?
[解决办法]
关注...

[解决办法]
我饿了
[解决办法]
优秀的程序员会写出优秀的程序。
如果让一个没有多少经验的人去写C#也照样会出现问题
[解决办法]
说实在的c++不实用,但我还在用
[解决办法]
bqtiger
C/CPP本质上是对冯诺体系的比较低lvl(所以高效)的抽象,除非冯诺体系出现了很大的变化。否则C/CPP会一直存在并流行下去。
这个主要说的是C.

Cpp,在面向一般应用的方面,与java,c#相比不具优势.

但在某些方面,仍找不到取代它的东西,如果你的程序很大,而且又很在意效率,也就
是你自己要写内存管理,而不是让别人帮你.这时候,还是需要CPP.

而且CPP现在作为一种万能语言(虽然学起来很难,写起来容易出错),但它毕竟是万能的
(通用的),还具有它的意义.



[解决办法]
我们只能说,“我们落伍了”,而不能说,“××落伍了”!
[解决办法]
日啊, 又来了
都是一些纯理论, 纯吹水的东西, 不管谁来说这个话题都是纯吹水的东西.
[解决办法]
说来说去还不都是自己写代码的水平问题

一个CIN又怎么样,还不是你自己没把缓冲区东西清掉. 在其他语言或许不会,编译器已经做好了

嘛.LZ想通过这个问题说明什么?

OO对象?LZ谁告诉你的OO思想就一定他妈是对的?

还是一句话,自己编码水平问题

读书人网 >C++

热点推荐