简单的C++模板继承问题

5
template <class T>
class baseclass{
protected:
    T data;
public:
    baseclass(){};
    void setData(T d);
};

template<class T>
void baseclass<T>::setT(T d){
    data = d;
}

上面展示的是我的基类,有一个受保护的成员变量和一个设置器。
template <class T>
class aclass : public baseclass<T>
{
    public:
        aclass(T d);
};

template<class T>
aclass<T>::aclass(T d){
     setData(d); <---WORKS
     data = d;   <---DOESN'T WORK
}

现在这是我对第一个类的子类。由于某些原因,直接访问受保护成员变量并不起作用,尽管我认为它应该工作。然而,访问setter(设置器)可以正常运行。我是C++的新手,我相信我错过了一些显而易见的东西。


如果你写成这样->data = d;,它能正常工作吗? - Michael Aaron Safyan
你能具体说明一下“不起作用”是什么意思吗?你是否遇到了编译器错误(如果有的话,是哪一个),还是在运行时什么都没有发生? - Jan Hudec
@Michael 是的,它确实如此。自然而然。 - jakev
1个回答

8
这个不起作用的原因是C++模板进行名称解析的一个怪异之处。特别是,如果你有一个模板类继承自另一个依赖于模板类型的类(就像在这个例子中所做的那样),你不能直接访问该基类的成员,除非给编译器一个关于查找位置的提示。这就是你得到错误的原因。
为了解决这个问题,你可以将构造函数重写为:
template<class T>
aclass<T>::aclass(T d){
     setData(d);
     this->data = d;
}

现在编译器知道data必须是aclass<T>的成员之一,它就可以找到它所要寻找的内容了。

有趣的是,你应该也会因为同样的原因在上一行得到一个错误提示。我不确定为什么它决定编译通过。为解决这个问题,你可以采取以下方式:

template<class T>
aclass<T>::aclass(T d){
     this->setData(d);
     this->data = d;
}

另外,您可以添加一个using声明来告诉编译器aclass从其父类继承了setData方法。在类声明中,考虑添加以下行:

template <class T>
class aclass : public baseclass<T>
{
    public:
        aclass(T d);

        using baseclass<T>::setData;
};

就像使用this->来访问数据成员一样,这个技巧可以使setData的来源变得明确,并帮助编译器知道你想要做什么。

希望这可以帮到你!


1
setData(d)之所以有效,是因为d依赖于模板参数。因此,在T未知之前,它不会被解析。在那时,我们也知道了实际的基类。 - Bo Persson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接