2011-06-25 5 views
2
​​

と仮想functions.Problem私はC++で少しプロジェクトをやっていると私は仮想関数に関するいくつかの問題に来ています。C++のvtable

私はいくつかの仮想関数を持つ基本クラスがある:

#ifndef COLLISIONSHAPE_H_ 
#define COLLISIONSHAPE_H_ 


namespace domino 
{ 
class CollisionShape : public DominoItem 
{ 
public: 
// CONSTRUCTOR 
//------------------------------------------------- 

// SETTERS 
//------------------------------------------------- 

// GETTERS 
//------------------------------------------------- 

    virtual void GetRadius() = 0; 
    virtual void GetPosition() = 0; 
    virtual void GetGrowth(CollisionShape* other) = 0; 
    virtual void GetSceneNode(); 

// OTHER 
//------------------------------------------------- 

    virtual bool overlaps(CollisionShape* shape) = 0; 

}; 
} 

#endif /* COLLISIONSHAPE_H_ */ 

CollisionShapeを拡張し

/* SphereShape.h */ 

#ifndef SPHERESHAPE_H_ 
#define SPHERESHAPE_H_ 

#include "CollisionShape.h" 

namespace domino 
{ 
class SphereShape : public CollisionShape 
{ 

public: 
// CONSTRUCTOR 
//------------------------------------------------- 
    SphereShape(); 
    SphereShape(CollisionShape* shape1, CollisionShape* shape2); 

// DESTRUCTOR 
//------------------------------------------------- 

    ~SphereShape(); 

// SETTERS 
//------------------------------------------------- 
    void SetPosition(); 
    void SetRadius(); 

// GETTERS 
//------------------------------------------------- 

    void GetRadius(); 
    void GetPosition(); 
    void GetSceneNode(); 
    void GetGrowth(CollisionShape* other); 

// OTHER 
//------------------------------------------------- 

    bool overlaps(CollisionShape* shape); 
}; 
} 

#endif /* SPHERESHAPE_H_ */ 

と.cppファイル上記の方法を実装SphereShapeクラス:

/*SphereShape.cpp*/ 
#include "SphereShape.h" 

#define max(a,b) (a>b?a:b) 

namespace domino 
{ 

// CONSTRUCTOR 
//------------------------------------------------- 

SphereShape::SphereShape(CollisionShape* shape1, CollisionShape* shape2) 
{ 
} 

// DESTRUCTOR 
//------------------------------------------------- 

SphereShape::~SphereShape() 
{ 
} 

// SETTERS 
//------------------------------------------------- 

void SphereShape::SetPosition() 
{ 
} 

void SphereShape::SetRadius() 
{ 
} 

// GETTERS 
//------------------------------------------------- 

void SphereShape::GetRadius() 
{ 

} 

void SphereShape::GetPosition() 
{ 
} 


void SphereShape::GetSceneNode() 
{ 
} 

void SphereShape::GetGrowth(CollisionShape* other) 
{ 
} 

// OTHER 
//------------------------------------------------- 

bool SphereShape::overlaps(CollisionShape* shape) 
{ 
    return true; 
} 

} 

これらのクラスは、他のクラスに沿って、共有クラスにコンパイルされます。 としょうかん。

Building libdomino.so 
g++ -m32 -lpthread -ldl -L/usr/X11R6/lib -lglut -lGLU -lGL -shared  -lSDKUtil -lglut -lGLEW -lOpenCL -L/home/adrian/AMD-APP-SDK-v2.4-lnx32/lib/x86 -L/home/adrian/AMD-APP-SDK-v2.4-lnx32/TempSDKUtil/lib/x86 -L"/home/adrian/AMD-APP-SDK-v2.4-lnx32/lib/x86" -lSDKUtil -lglut -lGLEW -lOpenCL -o build/debug/x86/libdomino.so build/debug/x86//Material.o build/debug/x86//Body.o build/debug/x86//SphereShape.o build/debug/x86//World.o build/debug/x86//Engine.o build/debug/x86//BVHNode.o 

私はこのライブラリを使用するコードをコンパイルすると、私は次のエラーを取得する:コマンドは、ライブラリを使用して、デモのコンパイルに使用

../../../lib/x86//libdomino.so: undefined reference to `vtable for domino::CollisionShape' 
../../../lib/x86//libdomino.so: undefined reference to `typeinfo for domino::CollisionShape' 

g++ -o build/debug/x86/startdemo build/debug/x86//CMesh.o build/debug/x86//CSceneNode.o build/debug/x86//OFF.o build/debug/x86//Light.o build/debug/x86//main.o build/debug/x86//Camera.o -m32 -lpthread -ldl -L/usr/X11R6/lib -lglut -lGLU -lGL -lSDKUtil -lglut -lGLEW -ldomino -lSDKUtil -lOpenCL -L/home/adrian/AMD-APP-SDK-v2.4-lnx32/lib/x86 -L/home/adrian/AMD-APP-SDK-v2.4-lnx32/TempSDKUtil/lib/x86 -L../../../lib/x86/ -L"/home/adrian/AMD-APP-SDK-v2.4-lnx32/lib/x86" 

を(-ldominoフラグ)

デモを実行すると、手動でライブラリは:

LD_LIBRARY_PATH=../../lib/x86/:$AMDAPPSDKROOT/lib/x86:$LD_LIBRARY_PATH bin/x86/startdemo 

仮想関数および仮想テーブルについて少し読んだ後、私は、仮想テーブルは、コンパイラによって処理されていることを理解し、私はそれを心配してはならないので、私は方法についての少し混乱していますこの問題を処理します。私はgcc version 4.6.0 20110530 (Red Hat 4.6.0-9) (GCC)

後に編集を使用してい

: 私は本当に申し訳ありませんが、私はここで直接手でコードを書きました。 コードで戻り値の型を定義しました。 下記の2人にお詫び申し上げます。

私はC++でより複雑なプロジェクトレイアウトを使用する際の初心者ですが、これはもっと複雑なmakefile、共有ライブラリ、そのようなものです。


私の問題は、私はvirtual void CollisionShape::GetSceneNode()の本体を定義していないという事実によって引き起こされました。

この問題を解決する方法は上記の関数を定義する、またはのような仮想純粋なそれを宣言するかのいずれかである:

virtual void CollisionShape::GetSceneNode() = 0; 
+0

どのようにリンクしていますか? – nullpotent

+0

@adivasile:問題をコンパイルして示す最小スニペットを投稿してください。あなたが戻り値の型を持たないという問題を解決しようとしたとき、関数が返す型を逆にしました。実際のシナリオとは何の関係もない赤ん坊の群れがあるときに、エラーを診断することは時折困難です。ライブラリを使用するコードのコマンドラインも指定してください。エラーが表示される場所です。 –

+0

@Michael Burr:ライブラリをリンクするコードを追加しました。スニペットでは、かなりのファイルや依存関係が存在するため、私が提供できるかどうかはわかりません。 – adivasile

答えて

3

非純粋な仮想関数は、決して使用されなくても定義する必要があります。欠けている定義は、特に、クラスの最初の非純粋で非インラインの仮想関数が未定義のまま残っている場合に、「vtable undefined」リンカーエラーを引き起こします。あなたの場合、CollisionShape::GetSceneNode()は未定義のままです。

関連のないメモでは、仮想関数を持つすべてのクラスには、例外なく、まったく例外がない仮想デストラクタが必要です。言語は残念なことにこれを強制するものではないので、あなたの責任です。 G ++にはフラグ-Weffc++があり、Scott Meyersの著書「Effective C++」に記述されている、これと他の一般的な落とし穴の警告を可能にします。このフラグは常に使用することを強くお勧めします。デフォルトで-Werrorを使うことも良い習慣です。コードを修正する可能性がない場合にのみ、個々の警告を1つずつ抑制します。

+0

-1 "仮想関数を持つすべてのクラスには仮想デストラクタが必要です"。カウンタの例として、COMのIUnknownインタフェースは3つの純粋仮想関数を持ち、仮想デストラクタを持たない。あなたがWindowsマシンを持っているなら、そのクラスから派生した何千ものクラスを使用する非常に多くのソフトウェアを使用しており、Windowsマシンの数でそれを掛けることができます。 –

+0

COMインターフェイスは、仮想デストラクタを持たないという効果を無効にする 'Release'メカニズムに依存しています。つまり、 'IUnknown'に対して' delete'を呼び出すことはないので、仮想デストラクタの振る舞いは必要ありません。ほとんどの場合、いくつかのインタフェースポインタで 'delete'が使用されることをサポートすることに興味があるので、一般的には仮想デストラクタが必要です。 – Pooven

-2

これは全体の問題ではないかもしれないが、あなたはそれらの戻り値の型が欠落しています機能。すなわちによりGetSceneNodeの矛盾宣言に

virtual double GetPosition() = 0; 
+0

いいえ、戻り値の型は 'cl_float'です。これは他の場所で定義されています。 – vsz

+0

継承されたクラスを投稿し、その両方をコンパイルする方法 – Leon

-1

、あなたの現在のコードベースクラスで

virtual void GetSceneNode(); 

、および派生クラスで

SceneNode* GetSceneNode(); 

で、あなたのコードはいけませんをコンパイルします。リンクの段階にはいけません。あなたが提示しているコードが実際のコードではないことは間違いありません。

したがって、私は質問を下落させました。

しかし、他のコードで明らかに生成されたエラーについては、SOに先に質問されており、たとえばhereと回答しています。

したがって、私も質問を終えるように投票しました。

乾杯& HTH。、

+0

ソースコード内の定義は正しいです。戻り値の型としてSceneNode *があります。スニペットをコンパイル可能にするために、その宣言を見落としました。私は謝罪します。ライブラリをコンパイルするように指定してから、それは問題ではないことに気がつきました。 – adivasile

+0

あなたの言うことのどの部分が正しいのか、間違っているのかを理解するために人々が適用すべき基準は何ですか? –

1

私はこれがあなたのコンパイルエラーを修正するかどうかを特定するために言うことはできませんが、いずれにせよ、あなたのCollisionShapeクラスで仮想デストラクタ(virtual ~CollisionShape())を宣言する必要があります。そうしないと、SphereShapeが基本クラスポインタ(CollisionShapeへのポインタ)によって削除されたときに、未定義のランタイムが発生します。もちろん、仮想コンストラクタが実際にクラスのvtblに追加されているので、これはエラーの背後にある原因である可能性の領域を超えていないと思います。

実効C++では、Scott Meyersは次のことを言います。

The C++ language standard is unusually clear on this topic. When you try to delete a derived class object through a base class pointer and the base class has a nonvirtual destructor [...], the results are undefined. That means compilers may generate code to do whatever they like: reformat your disk, send suggestive mail to your boss, fax source code to your competitors, whatever. (What often happens at runtimme is that the derived class's destructor is never called. [...])

+0

あなたの答えをありがとうが、私はすでにn.m..の助けを借りて問題を特定しました。私は 'CollisionShape :: GetSceneNode()'を実装していませんでしたし、純粋な仮想として宣言しませんでした。 – adivasile

+0

@adivasileあなたの問題を解決したと聞いてうれしい!より多くの人々があなたの質問に答えようとするのを防ぐために(そして同じものを持っているかもしれない他の人を助けるために)、あなたの答えをここに掲示し、それを受け入れてください。私が言ったように、あなたのコードがコンパイルされていても、依然として仮想デストラクタ*が必要です。 –

関連する問題