现在的位置: 首页 > 综合 > 正文

与封装性何干?

2013年09月14日 ⁄ 综合 ⁄ 共 1367字 ⁄ 字号 评论关闭

刚刚看到的一篇文章,关于C++的封装性(http://blog.csdn.net/ac1998/archive/2006/10/08/1326184.aspx),大致明白了作者的意思,只是觉得文中所提到的问题与封装性没什么关系,另外有的地方遣词用句让人误会,比方说这句:调用者看到了private里面的具体实现的细节!——这极大破坏了封装性。破坏了一个基本的OO原则。Java、C#、Delphi都有同样的private或protected,难道因为在private里面放了字段就破坏了封闭性吗?这个显然说不过去。

但我猜想,作者的意思应该是:由于C++用了分离模式进行编译和链接,所以,对于实现的任何改动,只要涉及到内存布局的改动,则实现者必须重新发布头文件

从上述观点来看,只要保证以下几点中的任意一点,就可以避免文中提到的问题:

  1. 只提供接口(纯虚类)
  2. 实现可以变,但内存布局不能变,不再增加和减少成员变量
  3. 避免分离编译和链接,所有函数均用内联

一、只提供接口

这样保证了只针对接口进行编程,但同时也使得对象无法在栈上被构造(在栈上构造有很多方便的地方,如离开作用域自动析构、不会生成内存碎片、速度快效率高等),而且必须提供相应的工厂,这样就增加了编程的难度,事实上,我还没有看到过哪个项目全用纯虚类的。

二、不改变成员变量的个数

用一种惯常的桥接手法,可以保证无论实现怎么变,类的成员变量个数都不变:


// foo.h
class FooImpl;
class Foo {
public:
Foo();
~Foo();
void funcA();
int funcB(int param);
...
private:
FooImpl * impl;
};

// foo.cpp
class FooImpl {
public:
void funcA() { ... }
int funcB(int param) { ... }
...
private:
...
...
};

Foo::Foo() : impl(new FooImpl) {}
Foo::~Foo() { delete impl; }
void Foo::funcA() { impl->funcA(); }
int Foo::funcB(int param) { return impl->funcB(param); }

 这种方式提供了一种灵活性,使对象可以被直接构造(无论是在栈上还是在堆上),但由于每一个成员函数都必须以CPP里被委托给Impl,要保证没有委托给错误的方法,只有靠人肉来保证,编译器没办法知道(除非委托给一个参数完全不同的方法),而且有的性能捍卫者会因为委托无法被内联而不愿意用这种手法(无论多小的函数,setter和getter都没办法内联在Foo.h里,都会有函数CALL的开销)。

三、避免分离编译和链接,所有函数均用内联

对于较小的类可以这样,对于较大的类,或者不愿意提供实现方法源代码,就不太适合了。


 总之,觉得文中想说的东西与“C++的封装性”一点关系也没有,如果全用内联,所有实现都写在头文件里,暴露的信息更多,反而可以完全避免文中所提到的问题,与封装性何干?

抱歉!评论已关闭.