2016-11-29 2 views
2

私はテンプレートを継承したいBaseクラスがあります。 Baseクラスには、テンプレート型についての前提となるpublicメソッドがあります。コードの簡略版は以下の通りである:GCC 6.2.0でこのコードをコンパイルサポートされていないタイプのC++でテンプレートクラスを継承する

#include <iostream> 

using namespace std; 

template <typename V> 
class Base { 
public: 
    virtual void print() { 
    a = "a"; 
    cout << "Base class" ; 
    } 
    void callIt() { 
    print(); 
    } 
    V a; 
}; 

class Derived : public Base<int> { 
public: 
    void print() override { 
    cout << "Derived class\n"; 
    } 
}; 


int main() { 
    Derived d; 
    d.callIt(); 
    return 0; 
} 

は私に、このエラーを与える:

test.cpp: In instantiation of 'void Base<V>::print() [with V = int]': 
test.cpp:13:10: required from 'void Base<V>::callIt() [with V = int]' 
test.cpp:28:12: required from here 
test.cpp:9:7: error: invalid conversion from 'const char*' to 'int' [-fpermissive] 
    a = "a"; 
    ~~^~~~~ 

私は完全にprint()方法のBaseクラスの実装を非表示にしますコンパイラから。どうやってやるの?

EDIT:皮肉なことに、ラインa = "a";をコメントアウトすると、コードが正常にコンパイルできるようにするとDerived classを出力します。

+0

なぜなら、 'Base ::'がより一般的なテンプレートに継承されることを意図している場合、 'Base :: print'は' V'についての仮定をしていますか? – Brian

+0

@Brian 'Base'は私がそれを制御できないライブラリの一部ですが、私はそれが提供する他の機能を望んでいます。 – Javad

+1

本当に楽しいことが分かりますか? 'a =" a ";'をコメントアウトし、出力を参照してください。 http://melpon.org/wandbox/permlink/Kci1HFRYtKbtbLk8 (Spoiler alert:出力は 'Derived class'とは何ですか?) –

答えて

2

printは仮想であるため、Base(コンパイラは適切なvtableを生成する必要があるため)を継承すると、その関数がまだ呼び出されていなくてもインスタンス化する必要があります。 printが非仮想メンバーの場合はそうではありません。この場合、呼び出されたときにのみインスタンス化されます。

私が考えることができる唯一の解決策は、あなたがここで仮想機能を取り除くことができるかどうかを確認することです - あなたができない場合は、申し訳ありませんが、あなたは運がありません。

+0

あなたは正しいですが、コードを単純化しすぎたと思います。私はちょうどコードを更新しました。 'print()'は 'Base :: callIt()'によって呼び出されています。古いコードで仮想を破棄することは助けになりますが、新しいコードではそれは役に立ちません。私は 'a =" a ";"をコメントアウトしてコードをコンパイルし、 'Derived class'ではなく' Base class'を得ました。この問題の解決策はありますか? – Javad

4

あなたがDerivedを宣言する前にBase<int>::print()のための特殊化を追加する場合それはあなたのコードが動作を取得することが可能です:

#include <iostream> 

using namespace std; 

template <typename V> 
class Base { 
public: 
    virtual void print() { 
    a = "a"; 
    cout << "Base class" ; 
    } 
    void callIt() { 
    print(); 
    } 
    V a; 
}; 

template <> 
void Base<int>::print() { 
    cout << "Specialization\n"; 
} 

class Derived : public Base<int> { 
public: 
    void print() override { 
    cout << "Derived class\n"; 
    } 
}; 


int main() { 
    Derived d; 
    d.callIt(); 
    return 0; 
} 

Live Demo

は、このかかわらずをやって注意してください:それはBaseの著者がについて行われた仮定を破りますどのタイプがテンプレートで動作し、ライブラリコードのバグを追跡するのが困難になる可能性があります。問題を特定するために簡素化

+0

なぜ 'Base :: callIt()'が必要ですか? @Javadはそれを 'Base'に追加することはできず、' d.print() 'の呼び出しはうまく動作します:http://melpon.org/wandbox/permlink/7bFxmV88g1izYBbc –

+1

OPのコードですから。 'Base :: callIt()'は、OPが 'Base :: print()'から 'virtual'修飾子を削除できない理由です。 –

+0

ああ、申し訳ありませんが、私はそれを見ませんでした。しかし、公平になるためには、コードをWandboxにコピーした後に元のポストに編集されました:) –

0

:中

template <typename V> 
class Base { 
public: 
    virtual void print() { 
    a = "a"; 
    } 

    V a; 
}; 

int main() 
{ 
    Base<int> b; 
} 

結果:我々は言って有効になっているので、

<source>:5:7: error: invalid conversion from 'const char*' to 'int' [-fpermissive] 
a = "a"; 

これは、次のとおりです。エラー理由だ

int a = "a"; 

そしてもちろん

intconst char*を割り当てることはできません。

Base<T>は、const char*からTへのアクセス可能な変換が存在しなければならないという制約で設計されています。

Tを他のものにしたい場合、この基本クラスは適切ではなく、あなたが望むもの(カプセル化?)を達成する別の方法を見つける必要があります。

関連する問題