私が次のoutside.h
ようなクラスを持っている場合:
class Outside
{
public:
Outside(int count);
GetCount();
}
extern
クラスをインスタンス化して呼び出す必要があるキーワードを使用して、framework.cppでどのように使用できますGetCount
か?
編集:
#include
許可されていません。
ここのみんなは少し優しすぎます。.hファイルを含めたくない理由はまったくありません。
それのために行き、ファイルを含めてください!
明確にするために。extern
クラスには不可能です:
class Outside
{
public:
Outside(int count);
GetCount();
}
ただし、framework.cppでクラスを使用できるようになると、 extern
タイプのオブジェクトを作成できますOutside
。その変数を宣言する.cppファイルが必要です。
#include "outside.h"
Outside outside(5);
そして、extern
(プロジェクトをコンパイルするときに正しいオブジェクトファイルにリンクしている限り)別のファイルでそのオブジェクトを参照できます。
#include "outside.h"
extern Outside outside;
int current_count = outside.GetCount();
extern
「このプログラムの実行時に、この名前のこのタイプの変数が存在することを知っているので、それを使用したい」という意味で使用されます。クラス、構造体、共用体、typedefなどではなく、変数/オブジェクトで機能します。オブジェクトと大差ありませんstatic
。
コンパイル時間を短縮するためにクラスを前方宣言することを考えているかもしれませんが、それには制限があります(オブジェクトは不透明なポインターとしてのみ使用でき、メソッドを呼び出すことはできません)。
また、の実装をユーザーから隠すことを意味する場合もありOutside
ます。そのためには、PIMPLパターンを確認する必要があります。
1つの可能性は、Outside.hに無料の関数を追加することです(名前空間も追加しました)。
namespace X {
class Outside {
int count_;
public:
Outside(int count) : count_(count) { }
int GetCount()
{
return count_;
}
};
int GetOutsideCount(Outside* o);
}
その関数を.cppファイルに実装します。その間、意図したグローバル変数を作成することもできますextern
(変数自体がポインターである必要はないことに注意してください)。
#include "outside.h"
namespace X {
int GetOutsideCount(Outside* o)
{
return o->GetCount();
}
}
X::Outside outside(5);
次に、プログラムでこれを実行します(outside
outside.hを含めなかったため、メソッドを呼び出すことができず、クラスまたはそれらのメソッドの新しい定義を追加して1つの定義ルールに違反したくないことに注意してください。定義が利用できない場合は、それ自体outside
ではなく、周囲にポインタを渡す必要がありますoutside
):
namespace X {
class Outside;
int GetOutsideCount(Outside* o);
}
extern X::Outside outside;
int main()
{
int current_count = GetOutsideCount(&outside);
}
控えめに言って、これは忌まわしいことだと思います。プログラムはGetOutsideCount
関数を見つけ、それを渡すことによってそれを呼び出しますOutside*
。 Outside::GetCount
は実際にはシークレットOutside
オブジェクトを受け取る通常の関数にコンパイルされているため(そのオブジェクトはポインターOutside::GetCount
を介して参照されます)、その関数を見つけて、に渡されたものを逆参照するように指示します。それは「長い道のり」と呼ばれていると思います。this
GetOutsideCount
Outside*
GetOutsideCount
しかし、それはそれが何であるかです。
キーワードの使用に慣れていない場合はextern
、代わりに、次の2つの関数を同じ方法で追加することで、完全な「C ++をCのように使用しましょう」モードに移行できます(つまり、前方宣言を使用し、次のすぐ隣に実装しint GetOUtsideCount()
ます。
Outside* CreateOutsidePointer(int count)
{
return new Outside(count);
}
void DestroyOutsidePointer(Outside* o)
{
return delete o;
}
私はそれを飲み込むことをいとわない。これは、 APRで使用されている戦略とよく似ています。
クラスを外部にしないでください。「outside.h」を含めて、のインスタンスを作成するだけですOutside
。
クラスをexternすることはできませんが、インスタンスを作成する関数をexternすることはできます。コンシューマーコードでは、次のようになります。
class Outside;
extern Outside* MakeAnOutside(int count);
extern int GetOutsideCount(Outside* outside);
次にoutside.hで:
Outside* MakeAnOutside(int count)
{
return new Outside(count);
}
int GetOutsideCount(Outside* outside)
{
return outside->GetCount();
}
しかし..これは良い考えではないかもしれません..
インクルードファイルは、クラス定義を含む定義用です。 extern
変数用です。
ソースファイルにクラスの定義がない場合、それを使用して実行できるのは、クラスを宣言しclass Outside;
、ポインタでインスタンスを渡すことだけです。構築、破棄、またはのようなメンバー関数の呼び出しなど、インスタンスを実際に使用することはできませんGetCount()
。このため、あなたはまったく必要ありませんextern
。別のソースファイル内の変数を参照する場合にのみ、それを使用して追加の操作を行うことはできません。
ここで使用しない正当な理由はありません#include
。唯一の代替手段は、ヘッダーファイルをコピーしてソースファイルに貼り付けることですが、これはかなり悪いことです。使用しないように言う人は#include
誰でもC++を理解していませんし、明らかにここで関連性があると思う人は誰も理解してextern
いません。
可能であれば、経験豊富なC ++開発者に、学習、優れたコーディングスタイルの確立、およびC++の開発方法の指導を依頼する必要があります。後で悪い考えになる他のことをしているのではないかと思います。
許可されていないばかげた要件がある場合は#include
、クラス宣言をコピーして.cpp
ファイルに貼り付ける必要があります。それは非常に悪い考えだと言う必要がありますか?
この要件の理由は何ですか?これを行う方法をアドバイスするのは辛いです。ソースファイルの長いパスを避けようとして#include
いる場合、これはビルドの問題であり、ソースコードの問題ではありません。
オプションを使用してインクルードパスにディレクトリを追加するgcc -I
か、コンパイラに相当するものを追加する必要があります。
あなたが本当に、本当にこれについて確信しているなら、あなたはこのようなものが欲しいでしょう:
// FIXME: Should #include "outside.h" but not allowed.
class Outside
{
public:
Outside(int count);
GetCount();
// Omitted
// void SomeUnusedMethod();
};
<code for framework.cpp here>
void UseOutside()
{
Outside o(5);
std::cout << o.GetCount() << std::endl;
}
次に、宣言をそのままにして、ヘッダーファイルから直接コピーアンドペーストすることを強くお勧めします。ただし、トリミングする場合は、使用しない非仮想メソッドを省略できます。すべての変数を保持する必要があります。
他の人が示唆しているように、ヘッダーを含めたり、クラス定義を複製したりせずに、クラスを「外部化」できるユースケースは1つしか考えられません。
クラスへのポインタを保持する必要があるが、直接逆参照することはなく、渡すだけの場合は、ファイルで次のことを実行できます。
class Outside;
class MyClass
{
Outside* pOutside;
void SetOutsidePointer(Outside *p) {pOutside = p;}
Outside* GetOutsidePointer() { return pOutside;}
/* the rest of the stuff */
}
これは、電話をかけたことがない場合、pOutside->GetCount()
またはnew Outside
ファイル内にある場合にのみ機能します。
外部クラスのインクルードをStdAfx.hまたはframework.cppがすでにインクルードしている他のヘッダーファイルに配置します。
あなたはストレージクラスを誤解していると思いますが、そのうちの1つは外部です。
「externとして宣言されたオブジェクトと変数は、別の変換ユニットまたは包含スコープで外部リンケージを持つものとして定義されたオブジェクトを宣言します。」
したがって、externのマーク付けは、クラスの定義/宣言ではなく変数用です。
したがって、.hを含めることができない場合は、.hと.cppを静的libまたはdllとしてビルドし、コードで使用することをお勧めします。
Yikes ...クラス(または他の)宣言を複数のcppファイル(コンパイル単位と呼ばれる)に複製するために、ヘッダーファイルにクラスを配置し、#includeを使用します。
#includeを実際に使用できない場合は、上記のように手動コピーが残ります。これには、誰かがオリジナルを変更すると古くなるという明らかな問題があります。これにより、クラッシュを追跡するのが困難になり、テストコードが完全に破壊されます。
この手動コピーのパスをたどることを主張する場合は、クラス宣言全体が必要です。技術的には、特定の部分を省略することもできますが、これは悪い考えです。明らかに、チームはC ++構造を深く理解していないため、間違いを犯す可能性があります。第二に、C++オブジェクトモデルはコンパイラ間で標準化されていません。理論的には、単純な非仮想メソッドでもモデルが変更され、テストが失敗する可能性があります。
「長いパス」は、ファイルを直接含めない大きな理由ではありません。しかし、本当にできない場合は、ヘッダーファイル全体を#includeがあった場所にコピーします。これは、Cプリプロセッサがとにかく行うことです。