C++扫盲

转载 2007年09月21日 00:56:00
C++扫盲
2007年09月14日 星期五 13:26

这段时间IT业炒作最多的可能就是Linus对C++的批判,本来在安焦水版上已经说明了我的一些观点,实在不应该再在Blog上说这个事,但看到连孟Y这样号称国内C++大师级的人物在讨论这个问题,看来我说说这个也不低级,我一直错把孟Y错当成翻译<<Undocumented Windows NT>>的董Y,大家不要搞错了,两个人在技术上的差别非常大,一个是CSDN的"C++大师",一个是同时精通英文,俄文和系统内核的高手.

不清楚的朋友先看一下原文:http://blog.csdn.net/myan/archive/2007/09/08/1777230.aspx

此君译过不少C++书,我没有看过他的(我通常只看潘爱民老师译的书),鉴于此君的一些话,我怀疑某些译书的质量到底如何。

安焦论坛上有个叫xtiger讽刺我本人是个学院派,呵呵!我不但不学院,我还是个十足的土八路,半路出家!我先简单说一下C++算是扫盲,不过我不会教你写Hello world,可能的话我尽量用解释C++的底层特性,再说一次,我不是极端主义者,不会狂热拥护某个东西或是人物,我只说出公道话.所以无论你是哪种极端,看完这篇Blog你不会有想骂的感觉,因为你会觉得很公平,这篇日志同样也包括有批评C++的成分.

一、什么是C++?
简单一点说,它就是带有面向对象功能的C语言增强版本,多了几个关键字以支持面向对象特性.C++语言的发明人BS原本命名C++为"含类的C",后来因为同事的一句玩笑话,改成"C++",这个"含类的C"后来也就以这个名称流传开来.

二、C++有什么特点?

首先,因为C++的国际标准ISO C++98要求C++必须包括ISO C89标准的全部特性(现在的C99标准并不全部包含),所以你所熟悉的C代码几乎可以一句不改的用C++编译器编译通过,但因为C++编译器对类型要求很严格,所以很可能用C++编译器来重新编译你的C代码时会发现以前不太会注意到的错误(或是警告),如果你是个C程序员,恭喜,你同时也是半个C++程序员,你以往的C编程经验完全不会被浪费,虽然你可能和我一样不喜欢Boost和ACE这样巨烂的库,但你还是个C++程序员,这和库没有关系.

现在的操作系统内核代码之所有大部分是C代码编写不是因为C++语言本身的问题,C++标准直到98年才定下来,而ANSI C却在成为正式标准前就已是事实上的标准,在这之前所有的厂商都对自己的C++做很变态的扩充,也许没有人记得Borland C++编译器当年是怎么把C++变成一个大怪物,让编译器直接支持成员函数响应Windows消息(通过一个变态的语法).在那个80年代C++大多数是这样变态的情况下,谁敢用它写内核?那个年代也流行结构编程思想,C+ASM方式写操作系统为大部分操作系统开发人员所熟悉和习惯.可是时代不同了,C++规范了但错过了最好的机会,而现在C已经写成的很稳定的内核,也没有必要再用C++去重写一遍,所以C++退居应用层开发,不得不承认这是个历史原因而不是技术原因,下面还是说说C++不同于C的地方吧(不一定全是优点,我也会挑出它的缺点,我不是个极端主义者),如果没有特指,C是指C89标准C语言.

特点一、单行注释
//你好,这是单行注释
事实上有些C编译器后来都吸收了C++的这个特点,所以不了解这两个语言历史的人会认为C本来就有这个特点.

特点二、新的IO流

cin>>val;
cout<<"Hello World"<<endl;
如果说的我够底层一点,这个不算C++的语言成分(估计真正的学院派会为这句话蹦出来开骂了),纯正的C/C++只有那么些关键字什么库函数都没有,问题是这些函数是你写还是编译器厂商写),它的基础是C++的运算符重载功能,在重载运算符函数里会调用操作系统的原生API进行输入输出,正是因为这个原因,所以这种IO方式是可扩展的(因为运算符可重载),比如我想输出一个结构SomeStruct,如果我用printf,我只能一个域一个域的输出(通常会被包装成一个函数,它的参数是结构指针),但在C++中我会重载<<运算符,在这个运算符函数(传结构的'引用',一种自引用指针)里面我还是通过一个域一个域的输出,但最后的调用方式是看起来cout<<SomeStruct<<endl让人从源代码级觉得编译器直接支持我输出这个结构,而不是多出一个输出包装函数,从某种义意上讲编译器成了可扩充的了.看你怎么想了!这个特性完全可以不使用,而直接使用操作系统的IO函数,如DebugPrint,WriteConsole,没有人规定你非要用这个.

特点三、结构、联合和枚举直接做类型名.
如果定义一个struct

struct SomeStruct
{
...
};

在真正的C语言中,你定义SomeStruct变量要写struct SomeStruct val;在C++中你使用SomeStruct val;这个特点和单行注释一样,现在的编译器大多数能同时编译C和C++代码,所以很多把这个特点融合到了C中,这也让一些程序员认为C语言也有这个功能.

特点四、局部变量随处声明
foo()
{
type val1;
type val2;
//some process
type val3;
type val4;
}

这样的代码,在C语言中是不合法的,但这却是很容易导致写出C++烂代码的特性,C++初学者不应该滥用这个特点,胡乱随处定义的变量会让函数/代码非常难以维护(我遇到过不少烂代码,当然我本人也写过很烂的,要不是安装了VA我有时真的不敢去面对那些巨烂的C++代码),通常的建议是比较小的函数可以随手定义变量,但大的复杂的函数,你可以分功能代码段,集中定义一些变量,每一段使用一些,下一段再定义一些.最让我感觉爽的是for(int i=0;i...;i++);类型这样的语法(C99好像也有这个功能,学C++的),这是for语句的增强,不过也可能理解是随处定义局部变量.

特点五、inline函数
如果你说C语言支持这个功能,那说明你还是不了解C语言,你会说__inline不是吗?那个和__try,__except一样是编译器的厂商扩展,不是语言内置的功能.公平一点说VC++常常会忽略掉你在C代码里写的__inline和你在C++代码里写的inline,它会自己决定是否内联,如果函数太大那就不会被内联,__forceinline比__inline和inline更好用一点,但同样的是函数也不能太大.

特点六、函数原形
C代码里你可以调用一个从来没有声明过的函数,编译器会假定参数全部合格,调用约定为__cdecl并且返回值为int型,直到它遇到这个函数为止,才会进行一些参数类型匹配,可能会给你一些警告.就是遇不到也可以编译通过,但到了link阶段编译器就报了"未决意的外部符号 int _SomeFunc(.....)....",如果编译器没有表现出这样的特点,那就是厂商增强了功能,而不是原始的ANSI C或是ISO C.

C++代码里你无可避免的要声明你要调用什么函数,类型是什么,参数有多少,分别是什么类型,在使用它们前编译器一定要先看到它们(哪怕是原型声明).

C中foo()原形表示可以没有参数,也可以有任意个参数,参数类型任意,但它在C++中的语意就是foo(void);这解释了为什么在写ShellCode时常用的FARPROC,在C中是万能API原型,到了C++中带了参数就编译不通过.

特点七、参数缺省值
这个C99标准好像也实现了,不太清楚,但大多数编译器支持的C89中肯定没有实现,C++的这个特点方便不少只是让你少敲几个字罢了,但如果你不指定参数的话编译器会帮你push缺省值给函数,在汇编代码这一层你才能看的更清楚.

特点八、函数重载
说简单一点就是参数列表(去掉带缺省值参数后)不一样,同时也可以返回值不一样,那么函数可以同名.举个例子,如果是算阶乘,你就没有必要为整数和浮点定分别起不同的名字定阶乘函数,如intMul,FloatMul.确切的说你还是写了两个函数,只是调用者觉得很爽(他认为一个阶乘函数支持两种数据类型).别跟我说用宏,宏我用的很化(合肥话出神入化的意思,呵呵!自吹一下),宏展开后可能带有侧效.

引用<<Programm the Microsoft Windows Driver Model>>中的一段:
驱动程序中使用的许多支持“函数”其实是DDK头文件中定义的宏.我们都知道应该避免在宏的参数中使用带有边效的表达式,原因很明显,宏可以多次使用其参数,见下面代码:

int a = 2, b = 42, c;
c = min(a++, b);

a的值是什么?(c的值又是什么?) 让我们看看这个似是而非的min宏:

#define min(x,y) (((x)<(y)) ? (x) : (y))

如果你用a++代替x,你将看到a最后等于4,因为表达式a++执行了两次.而“函数”min将返回3而不是2,因为函数的返回值是在第二次计算a++之前提取的a值.

而C++的语法中
inline int max(int a,int b)
{
return (a>b?a:b);
}
如何?这时候极端主义程序员又说了宏通用,可以用在任何类型,那我这样呢,如何?即没有侧效又很通用.
template<class type>
type max(type a,type b)
{
return (a>b?a:b);
}

再看一段代码(由VC++ 6.0编译通过,但gcc编译器也使用类似的方法)

int add(int a,int b)
{
return a+b;
}

float add(float a,float b)
{
return a+b;
}

int main(void)
{
int iv=add(1,2);
float fv=add(1.1f,2.2f);

return 0;
}
/*
第一段反汇编代码:
17: int iv=add(1,2);
004010B8 6A 02                push 2
004010BA 6A 01                push 1
004010BC E8 44 FF FF FF call @ILT+0(add) (00401005)
004010C1 83 C4 08 add esp,8
004010C4 89 45 FC mov dword ptr [ebp-4],eax
18: float fv=add(1.1f,2.2f);
004010C7 68 CD CC 0C 40 push 400CCCCDh
004010CC 68 CD CC 8C 3F push 3F8CCCCDh
004010D1 E8 3E FF FF FF call @ILT+15(add) (00401014)
004010D6 83 C4 08 add esp,8
004010D9 D9 5D F8 fstp dword ptr [ebp-8]

第二段反汇编代码:
@ILT+0(
?add@@YAHHH@Z):
00401005 E9 36 00 00 00 jmp add (00401040)
@ILT+5(
?id@?$ctype@G@std@@$D):
0040100A E9 41 01 00 00 jmp std::ctype<unsigned short>::id (00401150)
@ILT+10(
?id@?$ctype@G@std@@$E):
0040100F E9 DC 01 00 00 jmp std::ctype<unsigned short>::id (004011f0)
@ILT+15(
?add@@YAMMM@Z):
00401014 E9 57 00 00 00 jmp add (00401070)
@ILT+20(_main):
00401019 E9 82 00 00 00 jmp main (004010a0)

.map文件内容:
Address Publics by Value               Rva+Base Lib:Object

0001:00000040 ?add@@YAHHH@Z 00401040 f ccc.obj
0001:00000070
?add@@YAMMM@Z 00401070 f ccc.obj
...

重载函数真的同名了吗?只不过是编译器在内部帮你重命名了这两个函数,这就是所谓的"名字压延",重载运算符和重载成员函数也是如此.
*/

特点九、引用类型
这个类型我觉得很屎,跟很多操作系统的API都没有互动性,包括Linux和Windows,可能是从Pascal学来的,Pascal强调代码优美性,主要是清楚的表达算法是强类型的,指针运算也可,但不方便,类型要转来转去,做为C的超集C++,引入这个类型完全没有必要,做为C/C++程序员我们早已经习惯了指针,思考一下下面的代码
struct BadStru
{
int a;
int b;
};

BadStru &GetBadStru(void)
{
return *(BadStru *)NULL;
}

int main(void)
{
BadStru &bbb=GetBadStru();

bbb.a=100;???
return 0;
}

引用其实就是指针,只是编译器会帮你自动生成*(取内容)操作(有兴趣的调试时把VC++切换到反汇编视图看看引用是怎么工作的),在main中我如何确定bbb是一个空引用(其实就是空指针),因为bbb不是指针类型,所以我直接用bbb==NULL判断,C++类型检查很严格又编译不通过,只有在使用时用异常处理来发现(如果是在驱动中呢?BSOD),如果你没有发现这个引用类型的问题,那说明你的C++经验还不行.

所以我敢100%肯定所有使用MFC CListView::GetListCtrl(它返回CListCtrl&)函数的人都认为一定会返回一个有效的对象引用.但其实这是不严谨的!!你还应该使用GetSafeHwnd来判断一下.它底下这样实现:this==NULL?NULL,m_hWnd;有多少C++程序员想到过在成员函数中this竟然会是空指针呢!又有多少程序员想过你有可能会得到一个空引用呢.

特点十、内存管理
也就是两个运算符,new和delete,它们是可扩展的,C++编译器是这样来管理内存分配的,如果对象(结构)有自己的new,delete运算符,那就调用对象自己的,如果没有则搜索有没有全局的重载new和delete运算符,如果没有全局的那就用编译器自己的(其实也还是运算符函数,只不过是编译器厂商写的),通常它放在.lib文件里(可以是静态库,也可以是引入库).

不知道Linus所说的内存管理乱,他老人家有没有看过Numega DriverWorks中的类似这样的代码:
void* __cdecl operator new(
                                            size_t n,
                                            POOL_TYPE Pool
                                            )
{
return ExAllocatePool(Pool,n);
}

void __cdecl operator delete(void* p)
{
ExFreePool(p);
}

......
KLowerDevice* pComm = new(NonPagedPool)KLowerDevice(L//Devices//Serial0);
...
delete pComm;
也就是说内存怎么分配还是由我们自己控制的,如果是开发操作系统内核,那把ExAllocatePool和ExFreePool改成直接修改页(目录)表呢?我们甚至可以在驱动里指定在哪个内存池中分配,这样的可扩展性还不够啊!口味太高了一点吧,也许科学家程序员和我们这样的普通程序员的差别可能就在这里,我们要的是实用,不是老牛们所谓的艺术.

特点十一、对象机制
我在这里不想说什么OO,什么设计模式,那些都要建立要对象机制的基础之上,没有这些基础便没有OO.

一句话,对象就是结构,为什么,见下面的两段代码:
代码一:
#include <iostream>

using namespace std;

class object1
{
public:
object1():m_iTotalMoney(0)
{

}

void ShowMoney(void)
{
cout<<m_iTotalMoney<<endl;
}

void IncomingMoney(int iMoney)
{
m_iTotalMoney+=iMoney;
}

protected:
int m_iTotalMoney;
};

struct struct1
{
int m_iTotalMoney;
};

int main(void)
{
cout<<"object:"<<endl;
object1 obj;
obj.IncomingMoney(10000000);
obj.ShowMoney();
obj.IncomingMoney(20000000);
obj.ShowMoney();

struct1 *pObj=reinterpret_cast<struct1 *>(&obj);

cout<<"struct:"<<endl;
cout<<pObj->m_iTotalMoney<<endl;

return 0;
}

输出:
object:
10000000
30000000
struct:
30000000

Press any key to continue

代码二:
#include <windows.h>
#include <iostream>

using namespace std;

class object1
{
public:
object1():m_iTotalMoney(0)
{

}

void ShowMoney(void)
{
cout<<m_iTotalMoney<<endl;
}

virtual void IncomingMoney(int iMoney)
{
m_iTotalMoney+=iMoney;
}

virtual bool PayMoney(int iMoney)
{
if(m_iTotalMoney>=iMoney)
return (m_iTotalMoney-=iMoney,true);
  
return false;
}

protected:
int m_iTotalMoney;
};

typedef void (__fastcall *PFNIncomingMoney)(void *pThis,void *unused,int iMoney);
typedef bool (__fastcall *PFNPayMoney)(void *pThis,void *unused,int iMoney);

struct vtbl
{
PFNIncomingMoney pfnInComingMoney;
PFNPayMoney pfnPayMoney;
};

struct struct1
{
vtbl* m_vptr;
int m_iTotalMoney;
};

void __fastcall WhyHere(struct1* pThis,void *unused,int iMoney)
{
pThis->m_iTotalMoney=iMoney;
cout<<"why here?"<<endl;
}

int main(void)
{
object1 obj;

cout<<"object:"<<endl;
obj.IncomingMoney(100000);
obj.ShowMoney();
cout<<obj.PayMoney(50000)<<endl;
cout<<obj.PayMoney(50000)<<endl;
cout<<obj.PayMoney(50000)<<endl;

cout<<"struct:"<<endl;
struct1 *pObj=reinterpret_cast<struct1 *>(&obj);

pObj->m_vptr->pfnInComingMoney(pObj,NULL,100000);
cout<<pObj->m_iTotalMoney<<endl;
cout<<pObj->m_vptr->pfnPayMoney(pObj,NULL,50000)<<endl;
cout<<pObj->m_vptr->pfnPayMoney(pObj,NULL,50000)<<endl;
cout<<pObj->m_vptr->pfnPayMoney(pObj,NULL,50000)<<endl;

DWORD dwOld(0);
VirtualProtect(&pObj->m_vptr->pfnInComingMoney,4,PAGE_READWRITE,&dwOld);

*(DWORD*)(&pObj->m_vptr->pfnInComingMoney)=(DWORD)&WhyHere;

object1 *pObject=&obj;

pObject->IncomingMoney(20000);

obj.ShowMoney();
return 0;
}

输出:
object:
100000
1
1
0
struct:
100000
1
1
0
why here?
20000
Press any key to continue

你肯定很奇怪,对象怎么成了结构,编译器的确是这样告诉我们的,运行结果你也看到了,至于为什么会这样,建议你看看<<Inside C++ Object Model>>,但事实上我在看这本书以前就通过反汇编C++代码发现了这些本质的东西,只是后来看到这本书更证明了我的想法是对的.上面的代码通过Vc++ 6.0编译运行,事实上gcc是像我上面手工写的那样先将C++代码处理成C代码,再编译成.s汇编代码(这中间使用了"管道",所以你看不见中间文件,但你可以指定它生成这些中间文件),再汇编成.o文件,再ld由链接成可执行文件.

如果你没有发现对象即结构这个事实,我也可以肯定你很少写COM代码,因为MIDL编译器编译idl接口描述文件生成的.h文件里已经生成了类似我上面写的代码. 

特点十二、模板机制
说简单点就是编译器把模板函数或是类的代码当成一个模板,到用的时候再实例化出来一份,这个特性很好,但写的不好的模板类很容易导致代码膨胀,增加可执行文件大小,但写的好的模板代码却非常非常高效,即利用了对象机制,用又到模板的通用性机制,又将代码膨胀将到最低,将C++的效率发挥到极至,推荐看ATL的代码,C++本身非常好,写出C++烂代码的是人,是人的水平问题.

特点十三、名字空间

就是一种避免名字冲突的机制,它底层的机制还是"名字压延",就是使用C++的内部名称重命名一些符号。

特点十四、RTTI运行时类型信息

它的底层机制是基于和虚函数一样的虚表,我觉得完全可以在定义基类是就使用一个enum成员表示它是什么类型。这个机制除了可以让我们在反汇编时更容易得到类的相关信息以来几乎没有任何帮助,标准C++中的RTTI是个不上不下的功能,跟Object Pascal的RTTI机制相比功能差的很远(也正是因为Object Pascal的RTTI机制太强,所以DeDe利用了它,反出的汇编代码有非常多的类型注释超过IDA Pro),Microsoft的MFC实现了一套基于宏的更强大的RTTI机制(虽然还是不到Object Pascal的厉害),但至少可以让我在用OllyDbg分析时,找出最适合下断点的地方

特点十五、C++库
STL?Boost?ACE?...确切的说那不是C++原始语言的成分,是用C++语言写出来的类库,和C标准库是用C语言(有些是用汇编语言)写出来的函数库是一个概念,我看了Boost和ACE就胃部不适,我上面所说的才是纯正的C++语言特点.如果你非要像孟大师那样用类库中的类(std::string)去和纯C语言的char*做比较,我只能说你太无知了,在C++里我怎么就不可以用char*?shit!明明拉肚子,还非要吃油腻的东西,有病啊!!!明明知道内存不好管,就自己实现内存管理这一块呗,如果Numega的人也这么死呆呆的,我们就不会看到DriverStudio了.看看DriverWorks里的KUstring是如何的简洁高效.

啊呀!孟大师,我用STL或是Boost库中的包装类写不出ShellCode啊,怎么办啊!看来C++一点也不适合写ShellCode啊!有人用枪指着我非要用STL或是Boost写ShellCode???Boost库中的类不能在驱动里用啊,这么说C++一点也不适合写驱动啊!又有人枪指着我非要我在驱动里用Boost??? 呵呵!简直能笑死人.

最后要说的,用汇编语言去理解C/C++,多用C/C++/ASM混合编程,调代码时常常切换到反汇编视图看看,汇编中没有面向对象或是面向过程的概念,我们可以从机器的角度看C/C++动作的细节,而不要看表面的东西,否则你永远达不到你认为的自己对C/C++的掌握程度.而且不要像超女粉丝一样去追星追Linus,牛人也有说错话的时候,必竟Linus不是上帝.如果用推导,就是“因为尽信书不如无书,又因为书是人写的,所以不可以尽信任何一人所说的”,当然也包括我在这里所说的,我写的这些,你需要的是打开编程工具和调试器,自己实验一下.

一是自己的经验,二看了点资料。肯定会有不对的地方,大家可以直接回帖指出,或是开骂!都欢迎的!!!只求所有的话都基于“公平”二字。我不狂热拥护C++,也很崇拜Linus,但我看不愦不公平的说法。哪怕他是Linus、袁哥或是毛主席也好,有不对的地方,就一定要指出。

我自认为不是C++高手,如果说跟喜欢什么都自己写的人和喜欢狂用Boost和ACE这样烂库的人比较,我觉得自己处在中间,开发和运行效率我都要,但我也不用烂库.我做的还算是偏底层的东西吧,所谓的"抽像"和"设计"的功力还不行,还在学习中,也可能正是因为这点不足,所以我没有孟大师说的"心智包袱",反而可以看到期C++更本质的东西.我不反对C或是C++,因为我两个都喜欢,或者斗胆说一句精通吧!C++中的优点也说了,C++中我想骂的也骂了,over吧!


 
网友评论:
<script type="text/javascript"> function writecmt(type,id,cmtname,cmturl,portraitId){ var html1=""; if(type==1){ html1="<a name='"+id+"' href='"+cmturl+"' target='_blank' title='"+cmturl+"'><img border='0' src='http://himg.baidu.com/sys/portraitn/item/"+portraitId+".jpg'><br>"+cmtname+"</a>"; }else{ if(cmtname=="" || cmtname=="匿名网友"){ if(cmturl==""){ html1="<a name='"+id+"'>匿名网友</a>"; }else{ html1="<a name='"+id+"' href='"+cmturl+"' target='_blank' title='"+cmturl+"'>"+cmtname+"</a>"; } }else{ if(cmturl==""){ html1="<div class='f14' style='display:inline'>网友:<a name='"+id+"'>"+cmtname+"</a></div>"; }else{ html1="<div class='f14' style='display:inline'>网友:<a name='"+id+"' href='"+cmturl+"' target='_blank' title='"+cmturl+"'>"+cmtname+"</a></div>"; } } } document.write(html1); } </script>
1
匿名网友
2007年09月14日 星期五 17:27
你的问题在于你对C并不熟悉,对他们在具体项目中的优劣也不了解。
 
2
匿名网友
2007年09月14日 星期五 17:28
你写的东东都是在初等层次上的,建议你还是少上网,多做做实际的东东。
你学C++的时间很短。
我说得对吧?
 
7
<script type="text/javascript"> writecmt(1,"a25e18fab7a6e11da8d311ff","kruglinski","http://hi.baidu.com/kruglinski","a9896b7275676c696e736b691502"); </script>
kruglinski
2007年09月14日 星期五 20:02
把自己的几个回复合成一个:
我只知道在编译器一层,我了解他们也show给你看了,至于你所说的项目,我不知道是什么高深莫测的项目!用语言时间长短无所谓,关键是精髓的东西你掌握没有。我只用了四年又怎么样!

就"对象机制"那一部分,你觉得不了解C++的人可以解释清楚吗?

具体的一些东西,不是我在说话,是编译器生成的底层代码在说话,难道你没有看到?

"你的问题在于你对C并不熟悉"这种先入为主的说话方式,我觉得1楼可能是国内所谓通过CMM3,这个3那个4认证的软件公司里的,所谓的"总监"或是"经理"式的人物吧!你表明某个观点时也像我一样通过科学的方法来证明的吗?仅仅是"认为"而已吧!我最反感你这样的人,什么也不懂,还搞的好深沉,像很懂很专业的样子,还好我同事中这样的人不多。我不管几斤几两我敢show出来让大家骂!现在还流行的一句叫装什么来着!两个字的
 
8
网友:zk
2007年09月15日 星期六 04:10
在我这个菜鸟看来这是篇好文章,赞一个!
 
9
匿名网友
2007年09月15日 星期六 20:58
几次说到“烂库”让人觉得很不爽,这样极端的观点自己有就算了,放在网上如果影响到了初学者,就太恶劣了
 
11
<script type="text/javascript"> writecmt(1,"5890d0eddde6494c78f05594","kruglinski","http://hi.baidu.com/kruglinski","a9896b7275676c696e736b691502"); </script>
kruglinski
2007年09月15日 星期六 21:37
就像微软的那位朋友和Linus说的话“别拿可移植性说事儿,这是屁话(BS,bullshit)”一样,公平起见我对极端的C++程序员也要说这样的话,Boost、ACE之类的说移值,真移值时还是麻烦,我们不可能一点不在代码里用操作系统的API,这不是用几个库就可以解决的问题。

Boost库功能ATL几乎都有,效率不如ATL,方便不如MFC,不是烂库是什么。国内有多少人真正开发跨平台的东东,还不是在投资方面前吹牛,赚预算罢了。

应用层的东东,要么用运行效率最高的,要么用最好用的(也可能比较烂),即不好用,又烂的东东,没有必要。

编程初学者,我觉得学好C/C++本质的东西,学好数据结构和算法,再了解一下STL足已,如果想提高学点汇编语言、编译原理和操作系统核心方面的,如果连"深copy"/"浅copy"之类的机制都不清楚,只会用点库,唉...
 
12
网友:wingfiring
2007年09月15日 星期六 22:40
ATL?MFC?ATL还过得去,MFC就不要提了。
问题在于,ATL,BOOST都并非为国人定制。所以,以国人为名说BOOST是烂库未免自己斤两不够。
 
15
<script type="text/javascript"> writecmt(1,"1b917a3d926113ed3c6d9701","kruglinski","http://hi.baidu.com/kruglinski","a9896b7275676c696e736b691502"); </script>
kruglinski
2007年09月15日 星期六 23:51
你的这个话,就像是狂热的开发人员要求你开发一个操作系统来证明自己一样,我一个人没有能力写出Boost,不代表我不能说它烂,你去调试一下ACE,Boost内存泄漏有多少,而且一层调一层,一层调一层,不必要的抽像太多,可能是很"艺术",但效率太底。

MFC再不好它好用!它的优点就是易用性,ATL再难懂它高效,而且很贴近API层,合理的抽像合理的分层。
 
16
网友:TuotuoXP
2007年09月16日 星期日 18:06
赞!虽然黑底白字看得我眼睛疼,但是还是一口气看到底
很少能看到这样有味道的文章了,有机会好好交流一下 :)
 
17
<script type="text/javascript"> writecmt(1,"193e98198472ee4642a9ad41","鬼火狼烟","http://hi.baidu.com/balefire","6317b9edbbf0c0c7d1cc4c00"); </script>
鬼火狼烟
2007年09月19日 星期三 13:22
孟Y是C++大师?你也太抬举那娃了。。。。
1楼2楼的筒子连名字都不敢露,想必也是和孟丫一样的大师了,原来所谓的大师都是要么在CSDN上胡吹出来的不然就是到处顶个匿名的牌子放屁。
 
18
<script type="text/javascript"> writecmt(1,"2511f1b4c85477708ad4b24c","鬼火狼烟","http://hi.baidu.com/balefire","6317b9edbbf0c0c7d1cc4c00"); </script>
鬼火狼烟
2007年09月19日 星期三 13:28
TO 2楼:老K不写的"初等"一些,就凭你丫匿名大师的水平,你丫能看懂他写啥么
TO 老K:你丫也真是的,都一把年纪了,还和小毛孩一样到处惹骚。。。
 
19
<script type="text/javascript"> writecmt(1,"e568588dd3cc6011b21bba4e","鬼火狼烟","http://hi.baidu.com/balefire","6317b9edbbf0c0c7d1cc4c00"); </script>
鬼火狼烟
2007年09月19日 星期三 13:31
特点11不赞同,现在的新编译器已经不这样搞了
 
20
网友:kruglinski
2007年09月19日 星期三 15:20
关于11,至少VC++还会是这样,因为COM是***二进制兼容***的。而我使用VC6和VC8写的代码相互调用导出的COM接口都行,这就是证据!^_-

不过,我偶然发现VC6的sizeof(CWinApp)和VC8的sizeof(CWinApp)不一样,具体我还没有看是VC8的增加了CWinApp的内容还是,编译器底层的对象模型不一样。

最近在干嘛,怎么总不见上线?
 
21
<script type="text/javascript"> writecmt(1,"9f3fbfeef573662a2df534be","鬼火狼烟","http://hi.baidu.com/balefire","6317b9edbbf0c0c7d1cc4c00"); </script>
鬼火狼烟
2007年09月20日 星期四 12:46
天天在线,年底合同到期,这边美女太少,干活没激情,准备换个美女多点的窝~
 
22
<script type="text/javascript"> writecmt(1,"8b49590ebc9f8bc97bcbe1bf","鬼火狼烟","http://hi.baidu.com/balefire","6317b9edbbf0c0c7d1cc4c00"); </script>
鬼火狼烟
2007年09月20日 星期四 12:47
唉唉,以后要天天和VC打交道了。。。。
 

相关文章推荐

C++扫盲系列--第一个服务器程序

转自:http://blog.chinaunix.net/uid-22273897-id-393650.html 经过了近一个星期的反复纠结,今天要对于我的第一个服务器程序做一个小节。区区三百多...

c++ typename 关键字扫盲

typedef _CharT char_type; typedef _Traits traits_type; typedef typename traits...
  • statdm
  • statdm
  • 2013年01月08日 11:09
  • 4194

C/C++ socket网络编程扫盲篇

转载自:http://blog.csdn.net/sinat_20265495/article/details/51761554引言socket 是“套接字”的意思,是计算机之间进行通信的一种约定,也...

扫盲贴 Visual Studio 2005/2008中如何编译和运行C++程序

扫盲贴 Visual Studio 2005/2008中如何编译和运行C++程序         转载自:http://hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2/...
  • dtmine
  • dtmine
  • 2011年10月24日 20:31
  • 1078

扫盲队伍-报警讲义

  • 2012年01月31日 12:01
  • 13.84MB
  • 下载

SVM扫盲文档之四

  • 2012年10月24日 16:26
  • 296KB
  • 下载

【Unity Tips】备忘录(扫盲篇)

写在前面 Unity3D虽然是个非常方便的游戏引擎,但还是有一些地方会产生一些让人莫名其妙的问题,而且debug半天也不知道到底哪里错了。往往在经过了大量的log之后,也许我们才顿悟,原来Unit...

svm扫盲文档之六

  • 2012年10月24日 16:27
  • 291KB
  • 下载

[SIM扫盲包含ki破解软件

  • 2013年02月01日 15:55
  • 3.24MB
  • 下载

数字证书及CA的扫盲介绍

文章来源:http://kb.cnblogs.com/page/194742/ ★ 先说一个通俗的例子   考虑到证书体系的相关知识比较枯燥、晦涩。俺先拿一个通俗的例子来说事儿。 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++扫盲
举报原因:
原因补充:

(最多只允许输入30个字)