我可以为C ++类提供不完整的标题以隐藏实现细节吗?

all*_*llo 2 c++ api-design include

我想将一个类实现分为三个部分,以避免用户需要处理实现细节,例如,我用来实现功能的库:

impl.cpp

#include <api.h>
#include <impl.h>
Class::Class() {
    init();
}
Class::init() {
    myData = SomeLibrary::Type(42);
}
Class::doSomething() {
    myData.doSomething();
}
Run Code Online (Sandbox Code Playgroud)

展示次数

#include <somelibrary.h>
class Class {
public:
    Class();
    init();
    doSomething();
private:
    SomeLibary::Type myData;
}
Run Code Online (Sandbox Code Playgroud)

api.h

class Class {
    Class();
    doSomething();
}
Run Code Online (Sandbox Code Playgroud)

问题是,不允许我为类定义重新定义标题。当我定义这不起作用Class(),并doSomething()只在api.h,无论是。


一个可能的选择是定义api.h它,并且根本不在项目中使用它,而是安装它(而不安装impl.h)。

最明显的缺点是,我需要确保,在常见的方法api.h,并impl.h始终具有相同的签名,否则使用库会得到链接错误,在编译库时,我无法预测程序。

但是,这种方法是否会奏效,还是会由于obj文件与标头不匹配而引起其他问题(例如,指向类成员的指针错误或类似问题)?

Adr*_*ica 5

最简洁的答案是不!”

原因是:需要使用您的Class类的任何/所有“客户端”项目都必须具有该类的完整声明,以便编译器可以正确地确定诸如成员变量的偏移量之类的内容。

private成员的使用很好-客户端程序将无法更改它们-就像您当前的实现一样,标头中仅提供成员函数的最简单的概述,而(私有)源文件中包含所有实际的定义。

解决此问题的一种可能方法是在中声明一个指向嵌套类的指针Class,该嵌套类仅在共享标头中声明:class NestedClass然后,您可以在实现中使用该嵌套类指针执行所需的操作。通常,您可以使嵌套的类指针成为private成员。同样,由于在共享头文件中未给出其定义,因此“客户端”项目尝试访问该类的任何尝试(而不是作为指针)都将是编译器错误。

这是一个可能的代码故障(也许不是无错误的,因为它是一种快速的输入):

// impl.h
struct MyInternal; // An 'opaque' structure - the definition is For Your Eyes Only
class Class {
public:
    Class();
    init();
    doSomething();
private:
    MyInternal* hidden; // CLient never needs to access this! Compiler error if attempted.
}

// impl.cpp
#include <api.h>
#include <impl.h>

struct MyInternal {
    SomeLibrary::Type myData;
};

Class::Class() {
    init();
}
Class::init() {
    hidden = new MyInternal; // MUCH BETTER TO USE unique_ptr, or some other STL.
    hidden->myData = SomeLibrary::Type(42);
}
Class::doSomething() {
    hidden->myData.doSomething();
}
Run Code Online (Sandbox Code Playgroud)

注意:正如我在代码注释中所暗示的那样,最好使用代码std::unique_ptr<MyInternal> hidden。但是,这将要求您在自己的析构函数,赋值运算符和其他变量(移动运算符?复制构造函数?)中给出明确的定义Class,因为它们将需要访问该MyInternal结构的完整定义。