使用 PIMPL 惯用法,实现是否应始终是类的私有成员?



我已经看到PIMPL习惯用法以两种不同的方式实现。一种方法是始终使实现成为类的私有成员。这可确保无论如何都无法从类外部访问实现。

例如:

例子.h

#ifndef EXAMPLE_H
#define EXAMPLE_H
#include <memory>
class Example {
public:
void doSomething();
private:
struct Impl;
std::shared_ptr<Impl> pimpl_;
};
#endif /* EXAMPLE_H */

示例.cpp

#include "Example.h"
#include <iostream>
struct Example::Impl {
void doSomething() {
std::cout << "Hello World!" << std::endl;
}
};
void Example::doSomething() {
pimpl_->doSomething();
}

主.cpp

#include "Example.h"
int main() {
Example ex;
ex.doSomething();
system("pause");
}

我看到的另一种方法是使实现成为一个完全独立的类,具有自己的.h文件和自己的.cpp文件。

例如:

例子.h

#ifndef EXAMPLE_H
#define EXAMPLE_H
#include <memory>
struct ExampleImpl;
class Example {
public:
void doSomething();
private:
std::shared_ptr<ExampleImpl> pimpl_;
};
#endif /* EXAMPLE_H */

例子Impl.h

#ifndef EXAMPLE_IMPL_H
#define EXAMPLE_IMPL_H
struct ExampleImpl {
public:
void doSomething();
};
#endif /* EXAMPLE_IMPL_H */

示例.cpp

#include "Example.h"
#include "ExampleImpl.h"
#include <iostream>
void Example::doSomething() {
pimpl_->doSomething();
}

示例Impl.cpp

#include "ExampleImpl.h"
#include <iostream>
void ExampleImpl::doSomething() {
std::cout << "Hello World!" << std::endl;
}

主.cpp

#include "Example.h"
int main() {
Example ex;
ex.doSomething();
system("pause");
}

我能看到的唯一显着区别是使用第二种方法,您无需通过Example类即可访问实现。不过,我个人看不出有人需要这样做的任何理由。

这两种方法似乎都有效并满足最终目标,但是选择一种方法而不是另一种方法有什么真正的优势吗?

显然,这是一个意见问题。

我认为使用第二种方法违背了痘痘成语的精神。

  1. 实现的细节现在对外部可见。
  2. 如果对Example的界面进行任何更改,它很可能会影响四个文件而不是两个文件。
  3. 如果对ExampleImpl实现方式进行任何更改,则很可能会影响三个文件而不是一个文件。

鉴于上述几点,我建议使用嵌套类方法。

我实际上发现了第二种方法明显赢家的情况。如果需要从使用 PIMPL 习惯用法的类派生,以创建也使用 PIMPL 习惯用法的派生类,则可能会遇到继承问题。

如果派生类的实现类不继承自基类的实现类,您将无法在派生类的实现中使用任何继承的函数,这可能是一个完全的显示障碍!

除非有人能找到解决这个问题的简单方法,否则我将被迫使用第二种方法。

编辑:

事实证明,这个问题有一个解决方案,而无需采用第二种方法! 您可以简单地使派生类的实现类继承自基类的 NON 实现类!这为您提供了所有功能,没有任何麻烦!

最新更新