C++ 派生模板类访问基类成员数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1120833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:53:51  来源:igfitidea点击:

Derived template-class access to base-class member-data

c++templatesinheritancescopename-lookup

提问by Shamster

This question is a furtherance of the one asked in this thread.

这个问题是对这个线程中提出的问题的进一步推动。

Using the following class definitions:

使用以下类定义:

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!
}

When accessing the members of the template-class's base-class, it seems like I must always explicitly qualify the members using the template-style syntax of Bar<T>::_foo_arg. Is there a way to avoid this? Can a 'using' statement/directive come into play in a template class method to simplify the code?

在访问模板类基类的成员时,似乎我必须始终使用Bar<T>::_foo_arg. 有没有办法避免这种情况?“using”语句/指令可以在模板类方法中发挥作用以简化代码吗?

Edit:

编辑:

The scope issue is resolved by qualifying the variable with this-> syntax.

通过使用 this-> 语法限定变量来解决范围问题。

回答by sth

You can use this->to make clear that you are referring to a member of the class:

您可以使用this->来明确表示您指的是该类的成员:

void Bar<T>::BarFunc () {
    std::cout << this->_foo_arg << std::endl;
}

Alternatively you can also use "using" in the method:

或者,您也可以using在方法中使用“ ”:

void Bar<T>::BarFunc () {
    using Bar<T>::_foo_arg;             // Might not work in g++, IIRC
    std::cout << _foo_arg << std::endl;
}

This makes it clear to the compiler that the member name depends on the template parameters so that it searches for the definition of that name in the right places. For more information also see this entry in the C++ Faq Lite.

这使编译器清楚成员名称取决于模板参数,以便它在正确的位置搜索该名称的定义。有关更多信息,请参阅C++ Faq Lite 中的此条目

回答by songyuanyao

Here the base class is not a nondependent base class( which means one with a complete type that can be determined without knowing the template arguments), and _foo_argis a nondependent name. Standard C++ says that nondependent names are not looked up in dependent base classes.

这里的基类不是一个非依赖基类(意思是一个完整的类型可以在不知道模板参数的情况下确定),_foo_arg而是一个非依赖名称。标准 C++ 表示不会在依赖基类中查找非依赖名称。

To correct the code, it suffices to make the name _foo_argdependent because dependent names can be looked up only at the time of instantiation, and at that time the exact base specialization that must be explored will be known. For example:

为了更正代码,使名称_foo_arg依赖就足够了,因为依赖名称只能在实例化时查找,届时将知道必须探索的确切基础专业化。例如:

// solution#1
std::cout << this->_foo_arg << std::endl;

An alternative consists in introducing a dependency using a qualified name:

另一种方法是使用限定名称引入依赖项:

// solution#2
std::cout << Foo<T>::_foo_arg << std::endl;

Care must be taken with this solution, because if the unqualified nondependent name is used to form a virtual function call, then the qualification inhibits the virtual call mechanism and the meaning of the program changes.

必须小心使用此解决方案,因为如果使用未限定的非从属名称来形成虚函数调用,则限定会抑制虚调用机制并且程序的含义发生变化。

And you can bring a name from a dependent base class in the derived class once by using:

您可以通过以下方式从派生类中的依赖基类中获取一个名称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
}

回答by Daniel Earwicker

Appears to work fine in Visual C++ 2008. I've added some dummy definitions for the types you mentioned but gave no source for. The rest is exactly as you put it. Then a main function to force BarFuncto be instantiated and called.

似乎在 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();
}