用C ++分离接口和实现

时间:2013-12-17 20:37:09

标签: c++

如果我有一个简单的头文件:

namespace aNamespace {
    class AClass {
        public:
        AClass();
        ~AClass();

        bool Init();
        void Shutdown();
    };
}

在相应的CPP文件中实现此类的“正确”方法是什么?我可以看到两个选项:

选项A

namespace aNamespace {
    class AClass {
        public:
        AClass() { ... }
        ~AClass() { ... }

        bool Init() { ... }
        void Shutdown() { ... }
    };
}

选项B

namespace aNamespace {
    AClass::AClass() { ... }
    AClass::~AClass() { ... }

    bool AClass::Init() { ... }
    void AClass::Shutdown() { ... }
}

我在选项B 中看到的问题是,很难将特定于实现的成员添加到AClass - 例如如果实现需要std::wstring左右作为存储变量,该怎么办?但该变量未在头文件中定义?

我问这个的原因是因为我可能希望有AClass的多个实现,并根据某个外部变量(例如目标平台或架构)选择要链接哪个。

2 个答案:

答案 0 :(得分:2)

另一种选择是实际使每个实现平台的名称具体,并在头文件中有一个简单的typedef开关来控制根据目标/体系结构选择哪一个:

#ifdef target1
typedef AClass Target1ClassImplementation;
#elif  defined target2
typedef AClass Target2ClassImplementation;
#else
#error AClass is not implemented for current target
#endif

如果需要,可以将通用接口封装在派生自的基类实现中。它更不容易出错,因为在哪个实现是针对什么目标的意义上更明确,同时允许使用AClass而不管标头之外的平台目标。

答案 1 :(得分:0)

B在大多数情况下要好得多:

优点:

  • 隐藏实施细节。
  • 在头文件中减少#includes(较少暴露的依赖项!):
    • 更快的构建
    • 2个类可以调用彼此的功能。如果两者都在标题中,那就非常棘手。
    • 对实现的更改会影响其他类(构建时)。

缺点:    - CPP文件中的函数不在其他模块中内联(跨库边界)

最佳:确定最佳功能。将一个衬垫缩短到标头,将较长的衬垫缩短到cpp(s)。您可以为类实现提供多个源文件。