C/C++之冲突和共处

C没有抽象数据类型的能力,C++支持ADT,同时支持OO,而且还是多继承的OO,同时支持接口继承和实现继承。

所以引出一大堆问题和冲突。

其中最主要的是关于初始化的问题。

我们知道,C/C++严格区分初始化和赋值,很多人觉得挺奇怪,初始化不就是初次赋值么?呵呵,似乎就是,又似乎不是。初始化是在定义的时候赋值。

那位说了,这有啥好处?这涉及到一个程序状态正确性的说明性方法的问题。具体的说:就是涉及到断言的问题。

断言一般分为三种,静态断言、动态断言和不变性断言。所谓静态断言就是论断静态情况下成立的那种断言,初始化就是明显的静态行为。动态断言就是论断程序动态行为中符合的断言,典型的例子就是Eiffel的前置条件和后置条件或者叫做前提和结论。不变性断言是更高层次的断言,它论断程序永远遵从的限制,规定出程序的本质特征,对应于Eiffel的不变式。

其实初始化就是一个静态断言,表明该对象的值静态的等于这个静态初始化表达式的值。

C语言虽然不支持ADT,但是它支持Compound Data和数组,所以它的初始化方法也是比较复杂的。有兴趣的读者可以看看我的另一篇关于 = 0的blog里面涉及到C语言的初始化和组合字面值等问题。

C的初始化的基本语法举例如下:

int i = 6;
struct S
{
int a;
short b;
};
struct S o = {.a = 3, .b = 4};
...
另外还有数组,我就不举例了。

C++当然也可以用这些方法(其实现在似乎不能用,不过我相信以后会能用的),但是,C++又提供了一个更一致和抽象的方法——构造函数。

构造函数的语法如下:

class C
{
public:
C(int i, short s)
: _i(i)
, _s(s)
{}
private:
int _i;
short _s;
};

很多人批评他奇怪的语法,问为什么不像不同的方法一样写在{}里面,对于这个,我的想法是:由于这是一个静态断言,而不是一个赋值运算,所以这个特定的语法是合适的。

对于初始化,语法是这样的:

C o(3, 5);

当然了,也有人会这样写:

C o = C::C(3, 5);

这估计是为了照顾情绪低落的C程序员,主要是为了一个习惯,其实两者是一样的。

T o(initializeExpr)这种语法强烈的影响了C++的文化,甚至连原始类型都可以这样初始化了。

比如:

int i(0);

你可以认为int也是一种类型,它也有一个构造函数,甚至都可以有默认值……

这个统一看起来是小事一桩,其实对于template大有用处。而且还有更深层次的语义改变,你能看出来么?

我直说了,不管怎样T o = xxx这种语法都是不可重用的,你如果想规定第二个o也等于xxx你就得另写一遍或者使用赋值运算符,而如果你想给出一个稍有一点差别的但是基本规则相同的值,你用=语法就没有办法了。

而构造函数导致的T o(xxx)这个语法,使得你可以重用构造规定的一系列静态断言和赋值规则(顺便说一句,int i()保证i为0,这就是一种重用),第一种语法没有这个重用性。

C++的麻烦在于它有两种初始化的语法和语义,这会导致语言复杂,编译器复杂,最主要的是导致程序员迷惑,这是生产率的大敌。

不说了,赶快回家吃饭吧。

根据上面说的东西,大家一定会认为我赞成构造函数而反对复合字面常量,其实不是这样的。两者各有用处,相对来说,构造函数这种方式比较重量一些,复合字面常量轻量一些,联系现在流行的敏捷开发,现在流行的脚本式语言,我们可以感觉出来轻量级方法的优势。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值