【问题标题】:invalid use of incomplete type error无效使用不完整类型错误
【发布时间】:2016-03-19 16:34:50
【问题描述】:

这是简化的代码,只是为了说明我的问题:
main.cpp

#include "one.hpp"
#include <iostream>


int main(){
 One one;
 std::cout << one.two->val;
 }

一个.hpp:

struct Two; <- forward declare Two
struct One{
One();
~One() { delete two;}
Two* two;
};

一个.cpp

#include "one.hpp"
struct Two{
 int val;
};

One::One(): two(new Two()) {}

编译时我得到错误无效使用不完整类型“结构二”。 我假设由于 Two 是不完整的类型,我无法引用它的字段... 我想知道有没有办法在一个 cpp 文件中隐藏两个实现并使用这种前向声明在另一个 cpp 文件中使用它?问题来自创建 API,我想在某些类上隐藏实现。

【问题讨论】:

  • 当然可以,但是您通过尝试查看它违反了main 中隐藏的Two(如果不包含完整定义,则无法访问Two 的成员或方法是有效的Two)。
  • 谢谢大家的回答,关于析构函数的评论也很有帮助。所以我现在的理解是,使用这种前向声明来隐藏实现和类定义,即像在 pimpl idiom 中一样,只有当我们在一个定义发生的翻译单元中引用前向声明的类时才有意义,否则我将不得不引入类在每个使用其方法/字段的地方定义(因此不会隐藏类定义)。所以我认为我的设计决定是不正确的......
  • “我认为我的设计决策不正确” 我不确定我是否理解您是如何得出这个结论的。您也可以将实现隐藏在标题中。请参阅下面的示例。

标签: c++ api forward-declaration pimpl-idiom


【解决方案1】:

您不能删除不完整类型的对象。

解决方法是在 one.cpp 中也定义析构函数。

one.hpp:

struct One {
  ~One();
  // ...
};

one.cpp:

// ...

One::~One() { delete two; }

【讨论】:

  • 不要错过std::cout &lt;&lt; one.two-&gt;val; 中的main。那也行不通。
【解决方案2】:

Wikipedia:“不透明指针是一种向普通客户端隐藏接口实现细节的方法,因此可以更改实现而无需重新编译使用它的模块。 ":

向客户端发布的头文件:

struct opaque;
struct interface
{
  ~interface();
  void test();
  opaque* _p;
};

头文件未发布给客户端:

struct opaque
{
  void test();
  //...
};

interface实现文件:

#include "interface.h"
#include "opaque.h"

interface::~interface()
{
  delete _p;
}

void interface::test()
{
  _p->test(); 
}
// ...

opaque实现文件:

#include "opaque.h"

void opaque::test()
{
// actual implementation
}

【讨论】:

  • 好的,我明白了,但我仍然必须在每个引用转发结构的翻译单元中包含“结构定义”(想知道如果滥用它是否不会导致代码膨胀问题),无论如何都是好点只是为了创建私有头文件。
  • 包含实现头是正常的,因为客户端不依赖它。如果库的实现发生变化,关键是要缩短构建时间。
猜你喜欢
  • 1970-01-01
  • 2018-06-25
  • 1970-01-01
  • 2019-01-19
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2012-06-28
  • 1970-01-01
相关资源
最近更新 更多