C++ 使用未定义类型

C++ Use Of Undefined Type

本文关键字:类型 未定义 C++      更新时间:2023-10-16

我有以下类:

class Logger {
public:
DEFAULT_CONSTRUCTOR(Logger);
DEFAULT_DESTRUCTOR(Logger);
NO_DEFAULT_COPY_AND_ASSIGN(Logger);
bool Init(std::wstring logFileLocation, std::wstring assemblyVersion);
void Shutdown();
void const LogMessage(std::wstring message);
private:
struct LoggerImpl;
std::unique_ptr<LoggerImpl> impl; // Error here
};

但是,在尝试编译时,我收到以下错误:

// Errors:
// Error    1   error C2027: use of undefined type 'ophRuntime::Logger::LoggerImpl'
// Error    2   error C2338: can't delete an incomplete type    c:program files (x86)microsoft visual studio 12.0vcincludememory
// Warning  3   warning C4150: deletion of pointer to incomplete type 'ophRuntime::Logger::LoggerImpl'; no destructor called    c:program files (x86)microsoft visual studio 12.0vcincludememory

Logger::LoggerImpl相应的.cpp文件中有一个定义:

struct LoggerStream::LoggerStreamImpl {
LoggerStreamImpl(std::wstring componentName) : componentName(componentName) { }
const std::wstring componentName;
NO_DEFAULT_COPY_AND_ASSIGN(LoggerStreamImpl);
};

最后,这些宏的定义:

#define NO_DEFAULT_COPY_AND_ASSIGN(TypeName)    
TypeName(const TypeName&) = delete;         
void operator=(const TypeName&) = delete;   
TypeName(TypeName&&) = default;             
#define DEFAULT_CONSTRUCTOR(TypeName) TypeName();
#define DEFAULT_DESTRUCTOR(TypeName) ~TypeName();

在标头中声明析构函数,并在源文件中定义它。

在 .h 中

class Logger {
public:
Logger();  // default constructor
~Logger(); // default destructor
private:
struct LoggerImpl;                 // impl forward declaration
std::unique_ptr<LoggerImpl> impl;  // impl pointer
};

在.cpp

// Define the impl structure
struct Logger::LoggerImpl
{
};
// Define the default constructor
Logger::Logger() :impl(std::make_unique<LoggerImpl>())
{
}
// Define the default destructor
Logger::~Logger()
{
}

就是这样。

在你的情况下,你说LoggerImpl是这样在.cpp中定义的,但我没有看到LoggerImpl的定义,只是LoggerStreamImpl的定义。

唯一指针的参数类型必须是实例化唯一指针的翻译单元中的完整类型:

struct Foo;
std::unique_ptr<Foo> p;   // Error

当然,问题在于,如果没有完整的Foo类型,就无法定义唯一指针的析构函数。如果您需要某种痘痘,您可以通过将析构函数延迟到单独的翻译单元来解决这个问题:

template <typename T> struct Impl
{
Impl();
~Impl();
std::unique_ptr<T> impl;
};
struct Foo
{
struct FooImpl;
Impl<FooImpl> impl;
};
int main()
{
Foo f;
}

此翻译单元进行编译,因为Foo::impl的销毁留给析构函数Impl<FooImpl>::~Impl<FooImpl>,该析构函数已声明(模板类Impl<FooImpl>已完成),并且当前翻译单元中仅提供其定义

再次强调这一切的重点:这里介绍的 pimpl 结构允许您将类Foo::FooImpl的定义放入一个单独的私有翻译单元中,该类的使用者Foo永远看不到。这种解耦的代价是额外的动态分配(在Impl<T>的构造函数中)和额外的间接分配(在Foo的成员函数的定义中,未显示),以及缺乏Impl<T>::impl析构函数的内联。

有关更多详细信息,请参阅Herb Sutter的优秀GotW #101。