避免在类头文件中声明私有函数(C++)

23
(在C ++中)我有一个类,其结构在头文件中声明。该头文件包含在许多源文件中,因此当我编辑它时,需要重新编译许多文件。
该类有一组私有函数,仅在一个源文件中调用。目前,它们在头文件中的类结构中声明。当我添加这种类型的新函数或编辑参数时,它会导致许多文件的重新编译。我希望将函数声明在其他地方,以便只重新编译定义和调用它们的文件(以节省时间)。但是,它们仍然需要能够访问内部类变量。
如何实现这一点?

这些方法在我从头开始编写类时效果很好。然而,我并不是从头开始;这个类已经被写好了。 - user664303
4个回答

14

使用 pImpl 模式 - 在可见类中保留指向真实类的指针,并转发公共成员函数的调用。

编辑:回应评论

// Foo.h:

class FooImpl; // Do *not* include FooImpl.h
class Foo {
public:
  Foo();
  ~Foo();
  //.. also need copy ctor and op=
  int bar();
private:
  FooImpl * Impl;
};

// FooImpl.h:

class FooImpl {
public:
  int bar() { return Bar; }
private:
  int Bar;
};

// Foo.cpp:

#include "FooImpl.h"

Foo::Foo() { Impl = new FooImpl(); }
Foo::~Foo() { delete Impl; }
int Foo::bar() { return Impl->bar(); }

将类的实际实现保留在FooImpl中 - Foo应该拥有FooImpl公共成员的副本,然后只需转发这些调用。所有用户仅包含“Foo.h”,您可以更改FooImpl的所有私有细节,而不会使Foo的用户看到任何更改。


谢谢。总的来说这是个好主意。然而,在这种情况下,我一开始并没有使用这个框架,所以转换到它需要对我的类进行广泛的重写,包括编写所有公共函数的包装器。我希望能够轻松地从头文件中发布一部分私有函数,而不会遇到太多麻烦。 - user664303
1
@user664303:继承可能是一个解决方案 - 在我看来,这个特定问题是C++中令人讨厌的谬论之一。 - Erik
我想知道是否必须进行类实例指针的转换,例如:((priv_class *)this)->priv_func();。还是有避免这种情况的方法? - user664303
前置声明 - .h: class FooImpl; class Foo { public: void bar(); FooImpl * Impl; }; .cpp: #include "FooImpl.h" ... void Foo::bar() { Impl->bar(); } - Erik
@Erik:我不明白为什么FooImpl::bar()可以访问Foo的私有成员。我可以将Foo设置为FooImpl的友元,但我仍然需要向FooImpl::bar()传递指向Foo实例的指针。 - user664303
@user664303:Foo没有私有成员(除了Impl指针)——它只有与FooImpl相同的公共成员函数。请参见更新的答案及示例。 - Erik

6

无法在主类声明之外声明类成员函数。因此,如果您想在问题类之外声明能够访问特定类实例的成员变量的函数,则我认为除了将该实例传递给函数外别无选择。此外,如果您希望函数能够访问私有和受保护的变量,则需要将它们放入一个新类中,并使原始类成为该类的友元。例如:

header.h:

class FooImpl;

class Foo {
public:
   int bar();
   friend class FooImpl;
private:
   int var;
}

impl.cpp:

#include "header.h"

class FooImpl {
public:
   int bar(Foo &);
}

int FooImpl::bar(Foo &foo) {
return foo.var;
}

int Foo::bar() {
return FooImpl::bar(*this);
}

这是我目前的理解,但我并不100%确定。非常感谢您的评论。 - user664303
你在class Foo中仍然有int var。问题的整个重点不是将其移动到class FooImpl吗? - balki
3
@balki:不,这个问题的核心是如何在类中添加或编辑私有函数,而不改变头文件。如果我将私有变量移到FooImpl中,那么我还必须将所有现有的公共函数转发到该类。请参见我对Erik答案的第一个评论。 - user664303

2

1
创建一个抽象基类,其中只包含公共函数,并在您的头文件中引用此类。将您的实际类作为另一个实现。只有需要创建您的类的源文件才需要查看实现类头文件。

然后通过一个工厂函数隐藏创建 - AndresR
然后通过一个工厂函数隐藏创建 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接