11

是否有可能完成以下任务:

x.hpp - 此文件包含在许多其他类中

class x_impl; //forward declare
class x {
    public:
        //methods...
    private:
        x_impl* impl_;
};

x.cpp - 实现

#include <conrete_x>
typedef concrete_x x_impl;    //obviously this doesn't work
//implementation of methods...

所以基本上,我希望用户包含文件x.hpp,但不知道conrete_x.hpp标头。

由于我concrete_x只能通过指针使用并且它仅作为私有数据成员出现,因此前向声明应该足以让编译器知道为它准备多少空间。它看起来很像著名的“pimpl idiom”。

你能帮我解决这个问题吗?

PS。我不想使用 avoid*并对其进行投射..

4

4 回答 4

9

实际上,甚至可以对用户完全隐藏:

// Foo.hpp
class Foo {
public:

    //...

private:
    struct Impl;
    Impl* _impl;
};

// Foo.cpp
struct Foo::Impl {
    // stuff
};

我只想提醒你:

  • 您将需要编写一个适当的析构函数
  • 因此您还需要一个适当的复制构造函数、复制赋值运算符、移动构造函数和移动赋值运算符

有一些方法可以使 PIMPL 自动化,代价是一些黑魔法(类似于什么std::shared_ptr)。

于 2012-11-06T18:53:33.360 回答
5

作为@Angew 的答案的替代方案,如果concrete_x不应让 x 类的用户知道该名称,您可以这样做:

x.hpp

class x_impl;
class x {
  public:
    x();
    ~x();
    //methods...
  private:
    x_impl* impl_;
};

x.cpp中

#include <concrete_x>
class x_impl : public concrete_x { };

x:x() : impl_(new x_impl) {}
x:~x() { delete impl_; }
于 2012-11-06T18:20:12.350 回答
2

这仅在前向声明声明类的实际名称时才有效。所以要么将x.hpp更改为:

class concrete_x;
class x {
    public:
        //methods...
    private:
        concrete_x* impl_;
};

或使用x_impl标题中定义的类的名称<concrete_x>

于 2012-11-06T17:55:14.737 回答
0

That's what interfaces are for. Define an interface (pure virtual class) in your shared header file and give it to users. Inherit your concrete class from the interface and put it in the non-shared header file. Implement the concrete class in the cpp file (you can even define the concrete class inside the cpp).

于 2012-11-06T17:57:25.607 回答