0

我有一个项目,我必须将其从分离 .cpp/header 文件更改为将定义加入头文件中。我最初尝试将cpp文件的内容复制到头文件中,但我的ide - VS2012 express - 让我进入一个循环,它说头文件包含自身,所以当我删除包含“class.h”时它抱怨说在 Class::functionname 的情况下,无法识别 Class。最终我决定在标题本身中定义定义,例如

class Thing {
public:
   void func { code; } 
}

这解决了我在项目上的编译问题。问题是我有一个测试项目 - WinUnit - 我无法再访问这些功能。该项目曾经是一个静态库并进行了相应的链接,但由于没有 .cpp 文件,该项目没有生成 .lib。尝试更改为动态链接库,同样的问题 - 没有产生 dll。所以我添加了一个项目引用,当我输入#include“Class.h”时,它似乎可以识别我的类文件。

我的问题是它仍然没有编译类。它根本无法识别测试项目的 .cpp 文件中的类名。我什至尝试将头文件添加到测试项目中,但仍然没有乐趣。我尝试将附加包含目录设置为指向标题所在的位置 - 不好。

我怎样才能做到这一点?

编辑:仍然卡住了,所以我创建了一个 SSCCE,它运行良好,将测试项目指向附加包含目录中的头文件目录并且它运行正常。虽然主项目编译得很好,但我注意到它有一个智能感知错误 - 标识符“ClassName”未定义。所有其他类都识别其他类。#include "className" 存在。当我构建测试项目时,第一个错误与智能感知错误有关:错误1错误C2143:语法错误:缺少';' 前 '*'

实际的行是:ClassName * obj; - 这是一个私有变量。

测试项目有629个错误——其他一些代码:c4430、c2061。我想这些只是与未识别的类相关的初始问题的副作用......我迷路了,可以退出并重新考虑失败......

编辑:修复了智能感知错误,因此所有错误现在都在 Testproject 中 - 最多出现 826 个错误。包含头文件时看到头文件,但不识别任何类名。错误代码:c2061、c2065、c2923 等

4

2 回答 2

1

在您的示例代码func中是私有的,因为这是类内的默认访问。也许您想定义函数 public 以供您的测试代码和该类的其他客户端访问。

如果您只是将函数定义放在标题中,您还必须使它们内联。显式(对于自由函数和完全专用的函数模板定义)或隐式,即在类定义中定义类方法。

你是对的,库不再产生任何编译输出,即你既不需要链接 lib 也不需要链接 dll 文件。因此,在任何使用该库的项目中,包括您的测试项目,您不再需要指定要与该项目链接的库。毕竟,这是只有头文件库的原因之一:它们在编译时被完全包含(而不是链接时)。

如果您的测试项目之前编译过,它也应该在修改后编译,前提是您之前测试了所有库类并且没有对命名空间结构进行任何更改。

如果没有SSCCE和您从编译器中得到的正确错误,您只能猜测您可能陷入了哪些其他陷阱。

编辑:即使源到头的重构已经正确完成,我想到的一件事可能会导致麻烦是循环包含。如果你有这些,你必须要么打破依赖关系,要么把两个类放在同一个头文件中,在两个类定义之后提供方法定义(记住明确声明方法定义内联)

Edit2:循环包含的简单示例:A 类和 B 类都有一个调用另一个类的方法的方法。所以每个类方法的定义都需要其他类的方法的声明,即其他类的前向声明是不够的。在正常情况下,源将包括两个标题并完成。在仅标头的情况下,编译器将如下所示:

class A {
  B* b_;
public:
  A(B* b) : b_(b) {}
  void foo() {b_->meow();}
};

class B {
public:
  void bar() { A a(this); a.foo(); }
  void meow() { /* ... */}
};

编译器会抱怨 B 的使用和对B::meow(). 前者可以通过向前声明 B 来解决,后者不能。首先定义 B 无济于事,您将遇到与 A 和 相同的问题A::foo()。所以解决方案必须如下所示:

class A {
  B* b_;
public:
  A(B* b) : b_(b) {}
  void foo();   //1
};

class B {
public:
  void bar() { A a(this); a.foo(); }
  void meow() { /* ... */}
};

inline void A::foo() {b_->meow();} //2

依赖于第二类的第一类方法的定义必须延迟到第二类定义之后。由于 A 需要 B 而 B 需要 A,因此在仅包含标头的库中将此类混合类定义分隔在两个不同的标头中几乎没有意义。

分离此类事物的一种方法是打破依赖关系。在上述情况下,可能如下所示:

class B_Interface
{
public: 
  virtual void meow() = 0;
};

class A {
  B_Interface* b_;
public:
  A(B_Interface* b) : b_(b) {}
  void foo() {b_->meow();} //OK this time
};

class B : public B_Interface {
public:
  void bar() { A a(this); a.foo(); }
  virtual void meow() { /* ... */}
};

这是以增加一个间接为代价的,但分离了两个类的依赖关系,使 A 等的测试更容易。

于 2013-02-20T09:40:33.417 回答
0

我已经受够了,由于某种原因它仍然无法正常工作,这已经成为我的时间和精力的浪费。我回到了一个结构良好的项目,只有标题的地狱。

于 2013-02-21T20:50:12.593 回答