C++隐藏类声明中私有成员的手法示范(FCCM手法)

句龙胤 发布于 2015/08/21 23:59
阅读 1K+
收藏 3


// 我们这些自虐者们,在使用C++时,会遇到各种各样让人很头疼的问题,其中一个就是类声明。因为我们知道,类有公开成员和私有成员两大类,按照道路来说,无论如何在头文件中都不需要列出隐藏成员。
// 比如这个类:
class fuck
{
public:
    int Value();
private:
    int m_value;
};

// 我们并不希望在类声明中列出私有成员,因为这会有很大的问题,上面这个类看上去没什么问题,但如果是这样呢?
#include <SDL2/SDL.h>
#include <windows.h>
class fuck
{
public:
    ...
private:
    SDL_Surface* m_surface;
    HANDLE m_xxx;
    ...
};

// 你会看到,声明这个类,还需要包含两个重量级头文件,任何引用这个头文件的模块,都会被污染名称空间,不但会有函数、类型重名的隐患,还带来增加编译时间等各种各样非常FUCK的问题。

// 然而C++是一个异类,因为其为了“兼容C”的蛋疼决策,没有提供模块机制,所以每个.cpp都需要看到所有的东西,只要你想new一个类,都必须要要知道这个类的一切,才能正常的fuck一个class,因为C++需要知道,alloc一个类需要多少内存。

// 所以,如果想不用在类声明中列出私有成员,就需要使用各种蛋疼手法。我在这里介绍的就是一种主流的手法:FCCM。


为什么需要这样,还有一个很重要的原因,就是如果在类声明中列出私有成员,就会带来高耦合的蛋疼问题,你改变类的私有成员,每一个使用这个类的.cpp都需要重新编译,严重时可能还需要修改代码。

为了解决这个问题,一些自虐者们研究出了一种称为FCCM的手法,如下所示:


// fuck.h
class fuck
{
public:
    ...
private:
    class FuckCPP;
    FuckCPP* m;
};

// fuck.cpp
#include <SDL2/SDL.h>
#include <windows.h>
#include "fuck.h"
class fuck::FuckCPP
{
public:
    SDL_Surface* surface;
    HANDLE xxx;
    ...
};

fuck::fuck():m(new FuckCPP){m->surface = ...}
fuck::~fuck(){}
...

// cao.cpp
#include "fuck.h"

void begin_fuck()
{
    fuck a;
    a.Fuck("c++");
    ...
}



经过这样的手法之后,fuck.h中就只需要列出公开成员了,私有成员完全可以不用理,因为全部都在fuck.cpp中定义。其实这也是一个很多语言都在使用的技巧,就是一个类只有一个指针,任何地方创建类都只需要alloc一个容纳一个指针的内存,然后类成员的事就交给类的构造/析构函数。比如Java,用的就是这个手法。


总是要class FuckCPP; FuckCPP* m;就显得蛋疼了,所以我们可以将这段咒语弄成一个宏。

// fccm.h
#include <memory>
#define FUCK_CPP_CLASS_MODEL private: class FuckCPP; unique_ptr<FuckCPP> m;

// fuck.h
#include "fccm.h"
class fuck
{
    FUCK_CPP_CLASS_MODEL
public:
    void Fuck(const string& target);
    ...
};

// fuck.cpp
#include <SDL2/SDL.h>
#include <windows.h>
#include "fuck.h"
class fuck::FuckCPP
{
public:
    SDL_Surface* surface;
    HANDLE xxx;
    ...
};

fuck::fuck():m(new FuckCPP){}
fuck::~fuck(){}
...

// cao.cpp
#include "fuck.h"

void begin_fuck()
{
    fuck a;
    a.Fuck("c++");
    ...
}

这样,每个有类声明的头文件中包含fccm.h就行了,或者直接将那个宏放到类似stdafx.h这样的文件中。FUCK_CPP_CLASS_MODEL也是fccm手法的名称的来历,四个单词的首字母缩写。

细心的自虐者们可能还发现了,这样虽然非常有效的隐藏了私有成员,但在类定义中还是有些小问题,比如每个构造函数都重复了这段咒语:m(new FuckCPP),那么是不是也能弄个宏呢?

#define BEGIN_FUCK_CPP_CLASS_MODEL :m(new FuckCPP)

// fuck.cpp
...
fuck::fuck() BEGIN_FUCK_CPP_CLASS_MODEL {}
...



然而这并没有可行性,因为会带来一些莫名其妙的问题,比如在构造函数中会参数时,那么就需要很多个宏来满足1、2、3、···、n个参数的情况,所以不适用。

这就是C++让蛋疼的地方,你总是能遇到问题,你总是能解决问题,你总是解决的不完善。

好了,这期技术分享到此介绍,谢谢大家观看,FCCM。

加载中
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部