1

理解できない C++ コンパイラ エラーが発生し、修正方法や説明を見つけることができませんでした。問題を示すコード スニペットを次に示します。

#include <iostream>

template<class T>
class A {
public:
  A(int n) {data = new T[n]; }
  const T &operator()(int i) const {return data[i];}
protected:
  T *data;
};

template<class T>
class B : public A<T> {
public:
  B(int n) : A<T>(n) {}
  T &operator()(int i) {return this->data[i]; }
  //const T &operator()(int i) const {return this->data[i];} // fixes problem
};

template<class T, int N>
class C : public B<T> {
public:
  C() : B<T>(N) {}
private:
};

template<class T>
void doOp(const T &v) {
  std::cout << v(0) << std::endl;
}

void templateTest()
{
  C<double, 3> c;
  c(0) = 5;
  std::cout << c(0) << std::endl;

  doOp(c);
}

クラス B の行のコメントを外すと、コードは正しくコンパイルおよび実行されますが、クラス B でのこの演算子関数の定義がクラス A での定義と異なる理由がわかりません。

助けてくれてありがとう。

明細書

4

1 に答える 1

2

問題は、 への参照を介して非メンバー関数をdoOp()呼び出していることです。constconst

コメント行のコメントを外すと、実行可能なconstメンバー関数が見つかり、オーバーロードの解決によってそのバージョンの呼び出し演算子が選択されます。

その行のコメントを外さないと、サブクラスのオーバーロードされた呼び出し演算子によって隠されているため、呼び出し演算子の継承されたバージョンは見つかりません。

名前の隠蔽の問題を簡単な例で説明するために、次のプログラムを考えてみましょう。

struct X
{
    void foo() { }
};

struct Y : X
{
    void foo(int) { }
};

int main()
{
    Y y;
    y.foo(42); // OK
    y.foo(); // ERROR! Name hiding...
}

ここのコンパイラは への呼び出しを解決できません。これは、 が隠されているy.foo()ためです。X::foo()Y::foo()

usingこの問題を解決するには、次の宣言を追加しますY

struct X
{
    void foo() { }
};

struct Y : X
{
    using X::foo;
//  ^^^^^^^^^^^^^

    void foo(int) { }
};

int main()
{
    Y y;
    y.foo(42); // OK
    y.foo(); // OK
}

これで、両方の関数呼び出しが正しく解決されました。プログラムでは、基本クラスの同様のusing宣言を追加できます。operator ()

template<class T>
class B : public A<T> {
public:
    B(int n) : A<T>(n) {}
    T &operator()(int i) {return this->data[i]; }

    using A<T>::operator();
//  ^^^^^^^^^^^^^^^^^^^^^^^
};
于 2013-04-28T13:14:43.713 に答える