2016-06-24 16 views
0

C++で作業している間にかかっていました。私はSO、および他の場所(例:returning an abstract class from a functionHow do I make an abstract class properly return a concrete instance of another abstract class?)についていくつかの回答を試みましたが、まだ問題がありました。これらは完全には適合しないようです...C++を使用して抽象クラスを返す方法

私は持っています抽象クラス、派生クラス:

class AbstractClass { 
    virtual std::string virtMethod() = 0; 
} 

class Derived : public AbstractClass { 
    std::string virtMethod(); 
} 

また、私は抽象クラスの戻り値の型を取得しようとしている私の別々のクラスが(もちろん、派生クラスのインスタンスを返します)。

私はポインタと参照を使用して試してみた:

AbstractClass* methodFromOtherClass() { 
    if (somethingIsTrue) { 
     Derived d = Derived(); 
     return &d; 
    } 

    SomeOtherDerived s = SomeOtherDerived(); 
    return &s; 
} 

Xcodeで、私に警告を与える、:ローカル変数 'D' に関連付けられたスタックメモリの

アドレスは

を返さ

私は静的なDerivedオブジェクトを作成しようとしましたが、私の "methodFromOtherClass()"を呼び出すメソッドで破棄できませんでした。私もスマートポインタ(誰かがそれらの私の明白な誤用を指摘するかもしれませんが)で私の手を試してみた

std::unique_ptr<AbstractClass> methodFromOtherClass() { 
    if (somethingIsTrue) { 
     Derived d = Derived(); 
     return std::unique_ptr<AstractClass>(&d); 
    } 

    SomeOtherDerived s = SomeOtherDerived(); 
    return std::unique_ptr<AstractClass>(&s); 
} 

以上、おそらく当然、私にセグメンテーションフォルトを提供します。

私はこれをJavaで簡単に行うことができたことに慣れています...どんな助けもありがとうございます。現時点ではC++は私にとって非常に強力な言語ではないので、私は見落としている非常に基本的なものになる可能性があります。

+0

あなたの最後の試みはほぼ正しいです。 'std :: make_unique ();'を返します。 – nwp

答えて

1

あなたの基本的な問題(警告が示すように)は、あなたの関数がローカル変数のアドレスを返すことであり、その関数が復帰したときにローカル変数が存在しなくなるということです。

あなたの最初のバージョンは、これが行われたときに返されたポインタをdeleteし、呼び出し元が必要であることを

AbstractClass* methodFromOtherClass() 
{ 
    if (somethingIsTrue) 
    { 
     Derived *d = new Derived(); 
     return d; 
    } 

    SomeOtherDerived *s = new SomeOtherDerived(); 
    return s; 
} 

注に変更することができます。

第二のバージョンは、動的に割り当てられたオブジェクトを解放する義務から発信者を解放

std::unique_ptr<AbstractClass> methodFromOtherClass() 
{ 
    if (somethingIsTrue) 
    { 
     Derived *d = new Derived(); 
     return d; 
    } 

    SomeOtherDerived *s = new SomeOtherDerived(); 
    return s; 
} 

に変更することができます。

どちらの場合でも、AbstractClassには、返されたオブジェクトを解放するときの未定義の動作を避けるために、仮想デストラクタが必要です。

あなたの根底にある問題は、Javaがどのように動作するかを考えていることであり、C++はこの点でJavaとは大きく異なります。 Javaで類推してC++を習得しようとしないでください - このような場合、あなたは価値があるよりも自分自身でより多くの問題を作ります。 C++の観点からは、Javaはポインタと参照の概念を一つのものに融合させているので、JavaのようにC++ポインタや参照を使って作業することは、C++の問題のレシピです。

+0

ピーターに感謝します。私はあなたの受け入れられた答えをあなたのものに切り替えることになった。 6 +以上の言語の知識を実装しようとするようなものです。最近、抽象クラスの私の使用のほとんどはJavaから来ています。再度、感謝します – boycottInactivity

5

どちらの試みでも、同じ誤りがあります。ローカル変数へのポインタを返す。それは決してしないでください!必要なのは、ヒープメモリにクラスの新しいインスタンスを作成することです。

std::unique_ptrなし:

AbstractClass* methodFromOtherClass() { 
    if (somethingIsTrue) { 
     Derived* d = new Derived(); 
     return d; 
    } 

    SomeOtherDerived* s = new SomeOtherDerived(); 
    return s; 
} 

AbstractClass *c = obj->methodFromOtherClass(); 
... 
delete c; 

またはstd::unique_ptrと:

std::unique_ptr<AbstractClass> methodFromOtherClass() { 
    if (somethingIsTrue) { 
     Derived d = new Derived(); 
     return std::unique_ptr<AbstractClass>(d); 
    } 

    SomeOtherDerived* s = new SomeOtherDerived(); 
    return std::unique_ptr<AbstractClass>(s); 

    /* 
    Or better, with std::make_unique(): 

    if (somethingIsTrue) { 
     return std::make_unique<Derived>(); 
    } 

    return std::make_unique<SomeOtherDerived>(); 
    */ 
} 

std::unique_ptr<AbstractClass> c = obj->methodFromOtherClass(); 
... 
+0

'new'を使ったトリッキーは必要ありません。 'unique_ptr 'は暗黙的に 'unique_ptr 'に変換可能です。 – nwp

+0

@nwp - ありがとう、これは働いた。私はそれが私が見落としていた何かばかげたものでなければならなかった何かばかげたものでなければならないことを知っていた。これは、<>(オートコンプリートに頼るために得られるもの)の抽象クラスを使用する方法と、ヒープではなくスタックに作成する方法の組み合わせでした。 – boycottInactivity

+0

非常に迅速な対応のためにtkauslに感謝します。それを働かせることができました。 – boycottInactivity

関連する問題