避免在头文件中包含私有方法所需的内容

lex*_*x82 3 c++

与特定任务相关的类依赖于某个第三方库来执行此任务(比如 JSON 序列化)。该库的使用对于客户端应该是透明的,并且该类的公共接口中不会引用任何第三方代码类或数据类型。

在引入私有方法之前,我只需将所需的#includes 添加到 .cpp 文件即可。但是,现在我根据第 3 方代码声明了一个私有方法,我必须将一些 #include 拉到头文件中,这反过来又导致在所有其他文件(包括我的类的头文件)中包含相应的头。

我正在考虑使用函数而不是私有方法,这样我就不必在标头中声明函数。当然,我必须将对我正在使用的字段的引用传递给这些函数。这是解决此问题的合理方法吗?或者是否有在使用私有方法时实现这种封装的最佳实践?

Jar*_*d42 5

假设您必须添加那些私有方法

  • Json::Node AsJson() const;
  • std::string Serialize(const Json::Node& root) const;
  • Json::Node Unserialize(const std::string& document) const;
  • void InitFrom(const Json::Node&);

前向声明

假设Json是一个namespace,在标头中你只需要前向声明

namespace Json
{
    class Node;
}
Run Code Online (Sandbox Code Playgroud)

代替

#include <3rdLibrary/Json.hpp>
Run Code Online (Sandbox Code Playgroud)

如果Json是一个类并且是Json::Node一个内部类,则不能使用前向声明

自由函数 如果函数不需要私有访问(以及其他一些不需要虚拟的东西),您可以创建自由函数(在未命名的命名空间或static

所以 header 和 cpp 中没有任何内容:

#include <3rdLibrary/JsonCpp.hpp>
namespace {
    Json::Node AsJson(const MyClass& myclass) {/**/}
    std::string Serialize(const MyClass& myclass, const Json::Node& root) {/**/}
    Json::Node Unserialize(const MyClass& myclass, const std::string& document) {/**/}
    void InitFrom(MyClass& myclass, const Json::Node&){/**/}
}
MyClass::foo()
{
    Serialize(*this, AsJson(*this));
    /**/
}
Run Code Online (Sandbox Code Playgroud)

PIMPL IDIOM Pimpl idiom 是另一种选择

// header.hpp

class MyClass
{
public:
    ~MyClass();
    MyClass(const MyClass&); // = delete ?
    MyClass& operator =(const MyClass&); // = delete ?
    MyClass(MyClass&&); // = delete ?
    MyClass& operator =(MyClass&&); // = delete ?

    // previous public methods.
private:
    struct Pimpl;
    std::unique_ptr<Pimpl> pimpl;
};
Run Code Online (Sandbox Code Playgroud)

并在源中

// MyClass.cpp

struct Pimpl
{
    // What you should have done in MyClass
};

MyClass::~MyClass() = default; // which destroys Pimpl and should know Pimpl definition
                               // that's why it is not in header

ReturnType MyClass::publicMethod(Args args) {return pimpl->publicMethod(args);} // Same for all public methods.
Run Code Online (Sandbox Code Playgroud)

注意:可能可以使用 pimpl idiom 仅隐藏部分实现

界面

最后,与 pimpl 惯用语类似,您可以使用接口

// IMyClass.hpp
class IMyClass
{
public:
    virtual ~IMyClass() = default;
    IMyClass(const IMyClass&); // = delete ?
    IMyClass& operator =(const IMyClass&); // = delete ?
    IMyClass(IMyClass&&); // = delete ?
    IMyClass& operator =(IMyClass&&); // = delete ?

    // previous public methods but virtual.
};

std::unique_ptr<IMyClass> makeMyClass(Args);
Run Code Online (Sandbox Code Playgroud)

并正常实现MyClass(使用override)(其标头仅由其 cpp 文件使用)

并还实施

std::unique_ptr<IMyClass> makeMyClass(Args args) { return std::make_unique<MyClass>(args); }
Run Code Online (Sandbox Code Playgroud)

注意:可能可以通过接口仅公开某些部分(仅隐藏代码的某些部分)。