developer tip

기본 클래스 멤버 데이터에 대한 파생 템플릿 클래스 액세스

copycodes 2020. 12. 25. 10:19
반응형

기본 클래스 멤버 데이터에 대한 파생 템플릿 클래스 액세스


이 질문은 이 스레드 에서 요청한 질문의 지원입니다 .

다음 클래스 정의 사용 :

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 ++ Faq 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();
}

참조 URL : https://stackoverflow.com/questions/1120833/derived-template-class-access-to-base-class-member-data

반응형