3

変更している既存のコードの非表示の仮想メソッドについて、Sun C++5.10コンパイラからコンパイル警告が表示されます。何らかの理由で、作成者は特定のデータ型に対して関数のオーバーライドを実装していません。私はここで状況を再現しました:

// First the data types
struct Shape {};
struct Square : public Shape {};
struct Circle : public Shape {};
struct Triangle : public Shape {};

// Now the visitor classes
struct Virtual
{   
    virtual ~Virtual() {}

    virtual void visit( Square& obj ) {}
    virtual void visit( Circle& obj ) {}
    virtual void visit( Triangle& obj ) {}
};

struct Concrete : public Virtual
{   
    void visit( Square& obj ) {}
    void visit( Circle& obj ) {}
};

int main()
{   
    Concrete myConcrete;

    return 0;
}

Concreteクラスは実装されておらず、void visit( Triangle& obj ) {}これにより次のエラーメッセージが表示されます。

"pv_block.cpp", line 20: Warning: Concrete::visit hides the virtual function
Virtual::visit(Triangle&).

コードは正常に機能しますが、この警告メッセージを削除すると便利です。したがって、コンパイラが満足するように関数を実装したいのですが、現時点では明らかに必要ないため、使用できないように(できればコンパイル時に検出されるように)。

コンパイルを許可するが使用を防ぐためにコンパイルアサーションを実装する方法はありますか?BoostまたはC++11にアクセスできません。

4

4 に答える 4

5

なぜ使用を防ぎたいのですか?あなたが(どういうわけか)それを防いだとしても、次の(A)はコンパイルに失敗します:

Triangle t;
Concrete x;
x.visit(t);

次の(B)は引き続き機能します。

Triangle t;
Concrete x;
static_cast<Virtual&>(x).visit(t);

したがって、IMOは、呼び出されないようにすることは意味がありません。次のように、 using宣言Concreteクラスに追加することで警告を解決します。

struct Concrete : public Virtual
{ 
    using Virtual::visit;
    void visit( Square& obj ) {}
    void visit( Circle& obj ) {}
};

これにより、警告が無音になり、(A)が有効になります。しかし、この場合(A)を有効にするのは間違っているとは思いません。

于 2013-01-11T11:22:22.620 に答える
1

唯一の実際の解決策は、コンパイラの警告を無効にすることです。おそらく、基本クラスはデフォルトの実装を提供し、具象クラスはそれに満足しています。それ以外の場合は、基本クラスのデフォルトの実装に転送する実装を提供できます。

void Concrete::visit( Triangle& obj ) { Virtual::visit( obj ); }

個人的には、これは過剰な言い回しであり、むしろ避けたいと思います。

于 2013-01-11T11:18:14.200 に答える
1

私は必ずしもあなたのデザインに同意するわけではありませんが、警告は有効であり、再考するための例として注意する必要があると思います。ただし、これが必要な場合は、宣言をそこに配置して、アクセスを保護されたものなどに変更できます。

struct X {
   virtual void f() {}
   virtual void f(int) {}
};

struct Y : public X {
   virtual void f() {}
   virtual void f(int);
};

int
main() {
   Y y;
   y.f(10);
}

undefined reference to `Y::f(int)'
于 2013-01-11T11:08:13.130 に答える
1

したがって、コンパイラが満足するように関数を実装したいのですが、現時点では明らかに必要ないため、使用できないように(できればコンパイル時に検出されるように)。

Concrete::visit(Triangle&)これを行う1つの方法は、プライベートとして宣言することです。

struct Concrete : public Virtual
{   
   void visit( Square& obj ) {}
   void visit( Circle& obj ) {}
private:
   void visit (Triangle& obj);
};

実装の欠如に注意してください。myConcrete.visit(myTriangle)これにより、コンパイラの警告がなくなりますが、現在リンク時エラーの原因となっているコンパイル時エラーが変更されます。

この宣言があっても、オブジェクトを親クラスにキャストすることで、オブジェクトをConcreteオブジェクトにすることができます。これは問題であり、非常に大きな問題です。現状のコードは、リスコフの置換原則に違反しています。visitTriangleConcretestatic_cast<Virtual&>(myConcrete).visit (myTriangle)


usingAngewによって提案されたソリューション を使用する方がおそらく良いでしょう。これで、クラスの設計はリスコフの置換に従うことに近づきました。static_cast<Virtual&>(myConcrete).visit (mySquare)(および)に関するリスコフの置換に関しては、まだ問題があることに注意してくださいmyCircle

于 2013-01-11T12:38:30.377 に答える