0

.cpp/header ファイルを分離することから、定義をヘッダー ファイルだけに結合することへと変更しなければならなかったプロジェクトがあります。最初にcppファイルの内容をヘッダーファイルにコピーしようとしましたが、私のIDE(VS2012エクスプレス)がループに陥り、ヘッダーファイルにそれ自体が含まれていると言われたため、インクルード「class.h」を削除すると、 Class::functionname の場合、Class を認識できませんでした。最終的に、ヘッダー自体で定義を定義することにしました。

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

これにより、プロジェクトでのコンパイルの問題が修正されました。問題は、テスト プロジェクト (WinUnit) があり、関数にアクセスできなくなったことです。プロジェクトは以前は静的ライブラリであり、それに応じてリンクされていましたが、.cpp ファイルがないため、プロジェクトは .lib を生成しませんでした。ダイナミック リンク ライブラリに変更しようとしましたが、同じ問題 - dll が生成されませんでした。そこで、プロジェクト参照を追加しましたが、#include "Class.h" と入力すると、クラス ファイルが認識されたように見えました。

私の問題は、まだクラスをコンパイルしないことです。テスト プロジェクトの .cpp ファイル内のクラス名はまったく認識されません。テスト プロジェクトにヘッダー ファイルを追加しようとしましたが、まだ満足していません。ヘッダーがある場所を指すように追加のインクルードディレクトリを設定しようとしましたが、うまくいきません。

どうすればこれを達成できますか?

編集:まだスタックしているので、SSCCEを作成しました。正常に機能し、追加のINcludeディレクトリのヘッダーファイルディレクトリにテストプロジェクトを指定し、機能しました。メイン プロジェクトは正常にコンパイルされますが、Intellisense エラーがあることに気付きました - 識別子 "ClassName" が未定義です。他のすべてのクラスは、他のクラスを認識します。#include "className" が存在します。テスト プロジェクトをビルドすると、最初のエラーは次の行に関連しており、Intellisense エラー: エラー 1 エラー C2143: 構文エラー: ';' がありません。前 '*'

実際の行は次のとおりです。 ClassName * obj; - プライベート変数です。

テスト プロジェクトには 629 個のエラーがあります - その他のコード: c4430、c2061。これらは、クラスが認識されないことに関連する最初の問題の単なる副作用だと思います...迷ってしまい、これに失敗したことを撤回して再考することができます....

編集: インテリセンス エラーを修正し、すべてのエラーが Testproject に含まれるようになりました - 最大 826 エラーになりました。インクルード時にヘッダー ファイルを参照しますが、クラス名は認識しません。エラー コード: c2061、c2065、c2923 など

4

2 に答える 2

1

サンプルコードfuncでは、クラス内のデフォルトのアクセスであるプライベートです。テストコードやクラスの他のクライアントがアクセスできるように関数publicを定義したい場合があります。

関数定義をヘッダー内に配置するだけの場合は、それらをインラインにする必要もあります。明示的に(無料の関数および完全に特殊化された関数テンプレート定義の場合)、または暗黙的に、つまりクラス定義内にクラスメソッドを定義します。

ライブラリがコンパイルされた出力を生成しなくなったという点で正しいです。つまり、libファイルもdllファイルもリンクする必要はありません。したがって、テストプロジェクトを含め、ライブラリを使用するプロジェクトでは、そのプロジェクトにリンクするライブラリを指定する必要がなくなります。結局のところ、これがヘッダーのみのライブラリの理由の1つです。コンパイル時に(リンク時ではなく)完全に含まれるようになります。

テストプロジェクトが以前にコンパイルされた場合、以前にテスト対象のすべてのライブラリクラスがあり、名前空間構造に変更を加えなかった場合は、変更後にもコンパイルする必要があります。

SSCCEとコンパイラから得られる適切なエラーがなければ、他にどのような落とし穴に陥った可能性があるかを推測することしかできません。

編集:ソースからヘッダーへのリファクタリングが正しく行われた場合でも問題を引き起こす可能性があることの1つは、循環インクルードです。それらがある場合は、依存関係を壊すか、両方のクラスを同じヘッダーに入れて、両方のクラス定義の後にメソッド定義を提供する必要があります(メソッド定義を明示的にインラインで宣言することを忘れないでください)

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

2番目のクラスに依存する最初のクラスのメソッドの定義は、2番目のクラスの定義が終わるまで延期されます。AにはBが必要であり、BにはAが必要であるため、ヘッダーのみのlibには、このような混合されたクラス定義を2つの異なるヘッダーに分離する意味がほとんどありません。

そのようなものを分離する方法は、依存関係を壊すことです。上記の場合、次のようになります。

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() { /* ... */}
};

これにはもう1つの間接参照が必要ですが、2つのクラスの依存関係が分離され、Aなどのテストが容易になります。

于 2013-02-20T09:40:33.417 に答える
0

私は十分に持っていましたが、何らかの理由でまだ機能せず、時間とエネルギーの無駄になっています. 私はよく構築されたプロジェクトに戻ってきました。ヘッダーだけで地獄に落ちました。

于 2013-02-21T20:50:12.593 に答える