我正在尝试使用PIMPL习惯用法 - 对用户隐藏类的实现细节。我还想更进一步,隐藏实现类的实际名称。这也应该允许我通过更改一行代码来快速交换实现类。
我的方法如下:
在头文件中,我定义了一个Public
类,并声明了一个代理名称,Implementation
实现类。
X.h:
#pragma once
namespace detail {
class Implementation;
}
class Public {
public:
Public();
void foo();
private:
detail::Implementation* data;
};
在实现中,我定义了实际的实现类(使用不同的名称),然后使用 typedef 将Implementation
设置为我选择的类。
十.cpp
#include <iostream>
#include "X.h"
namespace {
class Private { //the actual implementation class. Everything about it, including its name, should be hidden
public:
void foo() { std::cout << "Hello world!" << std::endl; }
};
}
namespace detail {
typedef Private Implementation; //set Private as the actual Implementation
}
Public::Public() : data(new detail::Implementation()) {}
void Public::foo() {
data->foo();
}
不幸的是,我收到一个错误:
error C2371: 'detail::Implementation': redefinition; different basic types
在typedef
行中。但是在这两个位置(cpp 和 h 文件)中,我声明了一个类;一个提供了定义,另一个没有。那么我错过了什么?
如果typedef
(或C++11using
)由于原因无法使用,我还能如何实现我的目标?
我见过关于同一错误的类似问题,但我发现的只是一些微不足道的错误,例如:
- 错误 C2371:重新定义;不同的基本类型 - 为什么? :在定义之前使用名称 重定义;不同的基本
- 类型(typedef 结构),或 重定义不同的基本类型 => typedef:忘记包含保护
把你的 typedef 放在你的头文件中,并删除Implementation
的声明。
您声明Implementation
两次。一次在class Implementation;
,一次在typedef Private Implementation;
如果要隐藏Private
类型,请Public
模板化:
template<typename Implementation>
class Public
{
......
Implementation * data;
......
};
然后在 cpp 中,您可以使用私有实现将其声明为 :
Public<Private> my_thing;
更好的是,您可以按照最初的计划使用 typedef 隐藏模板:
typedef Public<Private> ExposedClass
定义实际的实现类(使用不同的名称),然后使用 typedef 将 Implementation 设置为我选择的那个类。
这就是问题所在。你不能。typedef 名称不是类。通过说class Implementation
,你承诺Implementation
将被定义为一个实际的类,而不是一个typedef名称。
摆脱typedef
并将Private
重命名为Implementation
。