您可以使用一个类跨多个cpp文件使用pimpl习语吗?



例如,我的意思是:假设您有一个头文件和一个pimpl类。您是否可以跨两个cpp文件定义该类的函数,而无需重新定义该类的变量?

在两个文件中使用指针的静态变量和重新定义之前,我已经尝试过了。然而,当跨文件移动时,我一直遇到关于类变量被擦除的问题。

//Header
class PRIVATE {
struct Test2;
public:
struct Test;
std::shared_ptr<Test> Client_ptr;
PRIVATE();
}; //PRIVATE
static std::shared_ptr<PRIVATE> PB = std::shared_ptr<PRIVATE>();
//Cpp1
//Implementation for Private
//Implementation for Test1
//Function not inside either class, references PB, defined in Cpp2  -> READ ACCESS VIOLATION
//Cpp2
//Definition Goes Here
//Implementation for Test2
//Function not inside either class, references PB, defined in Cpp1  -> READ ACCESS VIOLATION

通常在这种情况下,你会有一个公共标题,例如

#pragma once
class Foo {
Foo();
~Foo();
private:
struct FooPimpl;
FooPimpl* pimpl;
};

然后你会有第二个私有头文件(通常在你的源目录中,而不是包含目录)。private头文件将定义Pimpl结构体类型。

#pragma once
struct Foo::FooPimpl {
/*stuff*/
};

你需要在某处声明你的tors/dtors,例如

Foo.cpp

#include "public/Foo.h"
#include "./Foo.h"
Foo::Foo() {
pimpl = new FooPimpl;
}
Foo::~Foo() {
delete pimpl;
}

你可以使用相同的模式(例如,包括公共头,然后私有头)对所有其他源文件。

在不同的编译单元中拆分pimpl内部构件的一个问题是,您至少需要一个知道如何销毁所有成员的编译单元。

例如:

//main.h
class Main {
struct Test;
struct Test2;
std::unique_ptr<Test> pimpl1;
std::unique_ptr<Test2> pimpl2;
public:
Main();
~Main();
};
//test1.cpp
struct Main::Test {
};
// we don't know what Test2 is, so we cannot define Main::~Main().
//test2.cpp
struct Main::Test2 {
};
// we don't know what Test is, so we cannot define Main::~Main().

一个解决方案是:

class Main {
struct Test;
struct Test2;
std::unique_ptr<Test> pimpl1;
struct Defer {
std::unique_ptr<Test2> pimpl2;
Defer();
~Defer();
};
Defer defer;
public:
Main();
~Main();
};

现在,Main::Defer::~Defer()可以存在于test2.cpp中,它知道如何销毁它的pimpl2实例,但不需要知道如何销毁pimpl。同样,由于Main::Defer是在main.h中定义的(而不仅仅是声明的),Main::~Main()可以正确地销毁它的defer成员:

//test1.cpp
/* Test definition */
Main::Main() : pimpl(std::make_unique<Test>()), defer() {}
Main::~Main() {}
//test2.cpp
/* Test2 definition */
Main::Defer::Defer() : pimpl2(std::make_unique<Test2>()) {}
Main::Defer::~Defer() {}

TestTest2彼此交谈仍然很困难,但这就是粉刺的意义所在。它可以通过Main提供一些接口或通过一些中间头声明一些接口来实现。

最新更新