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中。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-06 09:30:45

C++对象模型----关于对象的相关文章

【转载】图说C++对象模型:对象内存布局详解

原文: 图说C++对象模型:对象内存布局详解 正文 回到顶部 0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看.本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有所不同.文章如果有解释不清.解释不通或疏漏的地方,恳请指出. 回到顶部 1.何为C++对象模型? 引用<深度探索C++对象模型>这本书中的话: 有两个概念可以解释C++对象模型: 语言中直接支持面向对象程序设计的部分. 对于各种支持的底层

C++对象模型——关于对象(第一章)

第一章    关于对象 在C语言中,"数据"和"处理数据的操作(函数)"是分开声明的,也就是说,语言本身并没有支持"数据和函数"之间的关联性.我们把这样的程序方法成为程序性,由一组"分布在各个以功能为导向的函数中"的算法所驱动,它们处理的是共同的外部数据.举个样例,假设声明一个struct Point3d,像这样: typedef struct point3d { float x; float y; float z; } Po

C++对象模型——临时性对象 (第六章)

6.3    临时性对象 (Temporary Objects) 如果有一个函数,形式如下: T operator+(const T &, const T &); 以及两个T objects,a和b,那么: a + b; 可能会导致一个临时性对象,以放置传回的对象.是否会导致一个临时性对象,视编译器的进取性(aggressiveness)以及上述操作发生时的程序上下关系(program context)而定.例如下面这个片段: T a, b; T c = a + b; 编译器会产生一个临时

浏览器对象模型BOM-window对象

一.window对象 1. window用以代表整个浏览器对象,用以这个对象对浏览器窗口进行操作.导航或者打开新的窗口.弹出系统对话框. moveBy(dx,dy) 把浏览器窗口相对于当前位置水平移动dx像素,垂直移动dy像素. moveTo(x,y)移动浏览器窗口,使它的左上角位于用户屏幕的(x,y)处. resizeBy(dw,dh)相对于浏览器的当前大小,调整窗口的大小.(dw,dh为负值减小窗口大小) resizeTo(w,h)把窗口调整为宽度w,高度为h.不能使用负值. IE  win

C++对象模型——暂时性对象 (第六章)

6.3    暂时性对象 (Temporary Objects) 假设有一个函数,形式例如以下: T operator+(const T &, const T &); 以及两个T objects,a和b,那么: a + b; 可能会导致一个暂时性对象,以放置传回的对象.是否会导致一个暂时性对象,视编译器的进取性(aggressiveness)以及上述操作发生时的程序上下关系(program context)而定.比如以下这个片段: T a, b; T c = a + b; 编译器会产生一个

JavaScript学习笔记——BOM_window对象

javascript浏览器对象模型-windwo对象(上) BOM Browser Object Model window对象 是BOM中所有对象的核心. 一.属性 1.(位置类型-获得浏览器的位置) IE: window.screenLeft 可以获得浏览器距屏幕左上角的左边距 window.screenTop 可以获得浏览器距屏幕左上角的上边距 //IE //左边距 //alert(screenLeft) //上边距 //alert(screenTop) FF: alert(screenX)

5月12日上课笔记-js 弹出框、函数、程序调试、基本事件、浏览器对象模型

一.弹出框 a.提示框 alert(); b.输入框 prompt(); c.确认框 confirm(); var flag= confirm("确认删除吗?"); 二.js程序调试 先看console控制台是否报错 浏览器debug alert(); console.log(); 三.函数 系统函数: parseInt(); 能够转换首字符是数字的字符串 Number();只能转换数字的字符串 isNaN(); is not a number //是不是非数字? 自定义函数: a.f

对象的串行化

一.串行化的概念和目的 1.什么是串行化 对象的寿命通常随着生成该对象的程序的终止而终止.有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复.我们把对象的这种能记录自己的状态以便将来再生的能力.叫作对象的持续性(persistence).对象通过写出描述自己状态的数值来记录自己 ,这个过程叫对象的串行化(Serialization) .串行化的主要任务是写出对象实例变量的数值.如果交量是另一对象的引用,则引用的对象也要串行化.这个过程是递归的,串行化可能要涉及一个复杂树结构的单行化,包括

javaScript---浏览器对象模型(BOM)

浏览器对象模型中把浏览器 的各个部分都是用了一个对象进行描述,如果我们要操作浏览器的一些属性,就可以通过浏览器对象模型的对象进行操作.top window 代表了一个新开的窗口 location 代表了地址栏对象. screen 代表了整个屏幕的对象 1.window对象go top 常用的方法: open() 打开一个新的窗口.(可设置工具栏.地址栏.窗口的大小等) resizeTo() 将窗口的大小更改为指定的宽度和高度值. moveBy() 相对于原来的窗口移动指定的x.y值. moveT