派生テンプレートクラスから基本クラスのメンバーデータへのアクセス
-
13-09-2019 - |
質問
この質問は、で尋ねられた質問をさらに発展させたものです。 このスレッド.
次のクラス定義を使用します。
template <class T>
class Foo {
public:
Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
{
/* do something for foo */
}
T Foo_T; // either a TypeA or a TypeB - TBD
foo_arg_t _foo_arg;
};
template <class T>
class Bar : public Foo<T> {
public:
Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
: Foo<T>(bar_arg) // base-class initializer
{
Foo<T>::Foo_T = T(a_arg);
}
Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
: Foo<T>(bar_arg)
{
Foo<T>::Foo_T = T(b_arg);
}
void BarFunc ();
};
template <class T>
void Bar<T>::BarFunc () {
std::cout << _foo_arg << std::endl; // This doesn't work - compiler error is: error: ‘_foo_arg’ was not declared in this scope
std::cout << Bar<T>::_foo_arg << std::endl; // This works!
}
テンプレートクラスの基本クラスのメンバーにアクセスするときは、常に次のテンプレート スタイルの構文を使用してメンバーを明示的に修飾する必要があるようです。 Bar<T>::_foo_arg
. 。これを回避する方法はありますか?コードを簡素化するために、テンプレート クラス メソッドで「using」ステートメント/ディレクティブを使用できますか?
編集:
スコープの問題は、変数を this-> 構文で修飾することで解決されます。
解決
あなたはクラスのメンバを参照していることを明らかにすることをthis->
を使用することができます
void Bar<T>::BarFunc () {
std::cout << this->_foo_arg << std::endl;
}
また、あなたはまた、この方法では、 "using
" を使用することができます:
void Bar<T>::BarFunc () {
using Bar<T>::_foo_arg; // Might not work in g++, IIRC
std::cout << _foo_arg << std::endl;
}
これは、適切な場所でその名前の定義を検索するようにメンバー名は、テンプレートパラメータに依存するコンパイラにそれが明確になります。詳細については、また、C ++よくある質問Liteのの中このエントリを参照してください。
他のヒント
ここでは基底クラスは、(テンプレート引数を知らなくても決定することができる完全な形のものを意味する)非依存基本クラスではなく、_foo_arg
は非依存の名前です。標準C ++は非依存の名前が依存基底クラスで検索されていないことを述べています。
のコードを修正するには、それは名前_foo_arg
を依存させるのに十分です。たとえばます:
// solution#1
std::cout << this->_foo_arg << std::endl;
の代替は、修飾名を使用して依存関係を導入して構成されています:
// solution#2
std::cout << Foo<T>::_foo_arg << std::endl;
修飾されていない非依存名は仮想関数呼び出しを形成するために使用されている場合、その資格は、仮想呼び出しメカニズムとプログラム変更の意味を抑制するため、ケアは、このソリューションで撮影されている必要があります。
そして、あなたはusing
一度派生クラスで依存基底クラスから名前をもたらすことができます:
// solution#3
template <class T>
class Bar : public Foo<T> {
public:
...
void BarFunc ();
private:
using Foo<T>::_foo_arg;
};
template <class T>
void Bar<T>::BarFunc () {
std::cout << _foo_arg << std::endl; // works
}
は、私はあなたが言及したが、何のためのソースを与えないタイプのためのいくつかのダミーの定義を追加したのVisual C ++ 2008で正常に動作しているように見えます。残りはあなたがそれを置くとまったく同じです。次いでBarFunc
を強制的にメイン関数がインスタンスと呼ぶことにする。
#include <iostream>
class streamable {};
std::ostream &operator<<(std::ostream &os, streamable &s) { return os; }
class foo_arg_t : public streamable {};
class a_arg_t : public streamable {};
class b_arg_t : public streamable {};
template <class T>
class Foo {
public:
Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)
{
/* do something for foo */
}
T Foo_T; // either a TypeA or a TypeB - TBD
foo_arg_t _foo_arg;
};
template <class T>
class Bar : public Foo<T> {
public:
Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
: Foo<T>(bar_arg) // base-class initializer
{
Foo<T>::Foo_T = T(a_arg);
}
Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
: Foo<T>(bar_arg)
{
Foo<T>::Foo_T = T(b_arg);
}
void BarFunc ();
};
template <class T>
void Bar<T>::BarFunc () {
std::cout << _foo_arg << std::endl;
std::cout << Bar<T>::_foo_arg << std::endl;
}
int main()
{
Bar<a_arg_t> *b = new Bar<a_arg_t>(foo_arg_t(), a_arg_t());
b->BarFunc();
}