C++对象模型——关键词所带来的差异(第一章)

1.2    关键词所带来的差异 (A Keyword Distinction)

    如果不是为了努力维护与C之间的兼容性,C++可以比现在更简单。举个例子,如果没有八种整数需要支持的话,overloaded function的解决方式将会简单得多。同样的道理,如果C++丢掉C的声明语法,就不需要判断下面这一行其实是pf的一个函数调用操作(invocation)而不是声明:
// 不知道下面是个declaration还是invocation
// 直到看到整数常量1024才能确定
int (*pf)(1024);
    而在下面这个声明中,像上面那样的"向前预览(lookahead)"甚至起不了作用:
// meta-language rule:
// pq的一个declaration,而不是invocation
int (*pq)();
    当语言无法区分是一个声明还是一个表达式(expression)时,需要一个超越语言范围的规则,而该规则会将上述表达式判断为一个"声明".
    同样地,如果C++并不需要支持C原有的struct,那么class的观念可以借由关键词class来支持。但令人惊讶的是,从C迁移到C++,除了效率,另一个最常被程序员询问的问题就是:什么时候应该在C++程序中以struct取代class?
关键词的困扰
    关键词struct本身并不一定要象征其后随之声明的任何东西,可以使用struct代替class,但仍然声明 public、protected、private 等等存取区段,以及一个完全 public 的接口,以及 virtual functions,以及单一继承、多重继承、虚拟继承等等。
    在C++中,选择struct或class作为关键词,用以导入ADT的理由是希望代码健全。
    在C所支持的struct和C++所支持的class之间,有一个观念上的重要差异。重点在于: 关键词本身并不提供这种差异,如果使用下面的定义类型,可以说这是一个class.
// struct名称(或class名称)暂时省略
{
public:
    virtual void foo();
protected:
    static int object_count;
};
    事实上可以它是一个struct,也可以说它是个class,这两种声明的观念上的意义取决于对"声明"本身的检验
    真正的问题并不在于所有"使用者自定义类型"的声明是否必须使用相同的关键词,问题在于使用class或者struct关键词是否可以给予"类型的内部声明"以某种承诺

策略性正确的struct (The Politically Correct Struct)
    C程序员的巧计有时候却成为C++程序员的陷阱,例如把单一单元的数组放在一个struct的尾端,于是每个struct objects可以拥有可变大小的数组:
struct mumber {
    /* stuff */
    char pc[1];
};
// 从档案或标准输入装置中取得一个字符串
// 然后为struct本身和该字符串配置足够的内存
struct mumble *pmumbl = (struct mumble *)
malloc(sizeof(struct mumble) + strlen(string) + 1);
strcpy(&memble.pc, string);
    如果改用class来声明,而该class是:
    指定多个access sections,内含数据
    从另一个class派生而来
    定义有一个或多个virtual functions
    那么或许可以顺利转化,或许不行。
    C++中凡处于同一个access section的数据,必定保证以声明次序出现在内存布局当中,然而被放置在多个access sections中的数据,排列次序就不一定了。
    同样的道理,base classes和derived classes的data member的布局也没有谁先谁后的强制规定。vitual function的存在也会使前面转化的有效性成为一个问号。
    如果需要一个相当复杂的C++ class的某部分数据,使它拥有C声明的那种样子,那么那一部分最好抽取出来成为一个独立的struct声明,将C与C++组合在一起的作用就是,从C struct中派生C++的部分:
struct C_Point {...};
class Point : public C_point {...}
    于是C和C++两种用法都可获得支持:
extern void draw_line(Point, Point);
draw_line(Point(0, 0), Point(100, 100));
draw_rect(Point(0, 0), Point(100, 100));
    这种习惯用法现已不再被推荐,因为某些编译器在支持virtual function的机制中对于class的继承布局做了一些改变, 组合(composition),而非继承,才是把C和C++结合在一起的唯一可行方法(conversion运算符提供了一个十分编译的萃取方法):
struct C_point {...};
class Point {
public:
    operator C_point() { return _c_point; }
private:
    C_point _c_point;
};
    C struct在C++中的一个合理用途,是当需要传递"一个复杂的class object的全部或部分"到某个C函数中去时,struct声明可以将数据封装起来,并保证拥有与C兼容的空间布局,然而这项保证只在组合(composition)的情况下才存在。如果是"继承"而不是"组合",编译器会决定是否应该有额外的data members被安排到base struct subobject中。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值