荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Dreamer (我与萤火虫), 信区: SoftDev
标  题: 【C++】[FAQ]为什么我必须把数据放到类的声明之中?
发信站: 荔园晨风BBS站 (Wed Jun  9 13:01:44 2004), 站内信件


Q: 为什么我必须把数据放到类的声明之中?
A: 没人强迫你这么做。如果你不希望界面中有数据,那么就不要把它放在定义界
面的类中,放到继承类中好了。参看“为何我编译一个程序要花那么多时间”条目
。[译注:本FAQ中凡原文为declare/declaration的均译为声明;
define/definition均译为定义。两者涵义之基本差别参见后面“‘int* p;’和‘
int *p;’到底哪个正确”条目中的译注。通常而言,我们还是将下面的示例代码
称为complex类的定义,而将单单一行“class complex;”称作声明。]

但也有的时候你确实需要把数据放到类声明里面,比如下面的复数类的例子:
template<class Scalar> class complex {
public:
complex() : re(0), im(0) { }
complex(Scalar r) : re(r), im(0) { }
complex(Scalar r, Scalar i) : re(r), im(i) { }
// ...

complex& operator+=(const complex& a)
{ re+=a.re; im+=a.im; return *this; }
// ...
private:
Scalar re, im;
};


这个complex(复数)类是被设计成像C++内置类型那样使用的,所以数据表示必须
出现在声明之中,以便可以建立真正的本地对象(即在堆栈上分配的对象,而非在
堆中分配),这同时也确保了简单操作能被正确内联化。“本地对象”和“内联”
这两点很重要,因为这样才可以使我们的复数类达到和内置复数类型的语言相当的
效率。

[译注:我觉得Bjarne的这段回答有点“逃避问题”之嫌。我想,提问者的真实意
图或许是想知道如何用C++将“界面”与“实作”完全分离。不幸的是,C++语言和
类机制本身不提供这种方式。我们都知道,类的“界面”部分往往被定义为公有(
一般是一些虚函数);“实作”部分则往往定义为保护或私有(包括函数和数据)
;但无论是“public”段还是“protected”、“private”段都必须出现在类的声
明中,随类声明所在的头文件一起提供。想来这就是“为何数据必须放到类声明中
”问题的由来吧。为了解决这个问题,我们有个变通的办法:使用Proxy模式(参
见《Design Patterns : Elements of Reusable Object-Oriented Software》一
书),我们可以将实作部分在proxy类中声明(称为“对象组合”),而不将
proxy类的声明暴露给用户。例如:
class Implement; // forward declaration
class Interface {
public:
// interface
private:
Implement impl;
};
在这个例子中,Implement类就是proxy。在Interface中暴露给用户的只是一个
impl对象的“存根”,而无实作内容。Implement类可以如下声明:
class Implement { public: // implementation details, including data
members
};

上述代码中的注释处可以存放提问者所说的“数据”,而Implement的声明代码不
需暴露给用户。不过,Proxy模式也不是十全十美的——Interface通过impl指针间
接调用实作代码带来了额外的开销。或许读者会说,C++不是有内联机制吗?这个
开销能通过内联定义而弥补吧。但别忘了,此处运用Proxy模式的目的就是把“实
作”部分隐藏起来,这“隐藏”往往就意味着“实作代码”以链接库中的二进制代
码形式存在。目前的C++编译器和链接器能做到既“代码内联”又“二进制隐藏”
吗?或许可以。那么Proxy模式又能否和C++的模板机制“合作愉快”呢?(换句话
说,如果前面代码中Interface和Implement的声明均不是class,而是template,
又如何呢?)关键在于,编译器对内联和模板的支持之实作是否需要进行源码拷贝
,还是可以进行二进制码拷贝。目前而言,C#的泛型支持之实作是在Intermediate
 Language层面上的,而C++则是源码层面上的。Bjarne给出的复数类声明代码称“
数据必须出现在类声明中”也是部分出于这种考虑。呵呵,扯远了……毕竟,这段
文字只是FAQ的“译注”而已,此处不作更多探讨,有兴趣的读者可以自己去寻找
答案 :O) ]





--
如果你真的爱萤火虫,你就不应该将她困在瓶子里;
如果你真的爱萤火虫,你应该放开她,让她在天空中自由自在地飞!
虽然你会不舍得她,但是最终你就会明白这样你才真正拥有了她!

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.223]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店