C++模板继承

17

我是一名新的C++程序员,第一次使用模板。

我有一个抽象类和另一个继承它的类。但是抽象类中所有受保护成员在另一个类中都无法被识别:

class0.h:

template<class T>
class class0 {

protected:
    char p;
public:
    char getChar();
};

**class1.h**
template<class T>
class class1:public class0<T> {
public:
    void printChar();
};
template<class T>
void class1<T>::printChar(){
    cout<< p<<endl;//p was not declared in this scope
}

谢谢。祝您有美好的一周 =)


你的基类需要一个公共虚析构函数,或者是一个受保护/私有的非虚析构函数。 - GManNickG
顺便问一下,这个类中哪一个是抽象的? - Chubsdad
4个回答

26

出现这种情况是因为模板查找规则。

p 不是一个依赖表达式,因为它只是一个标识符,而不是依赖于模板参数的东西。这意味着依赖于模板参数的基类不会被搜索来解析名称 p。为了解决这个问题,您需要使用一些依赖于模板参数的东西。使用 this-> 就可以做到这点。

例如:

cout << this->p << endl;

@GMan:我不知道;litb现在已经发布了一个答案。 :-) - CB Bailey
我只是在挑剔这个小细节 :) - Johannes Schaub - litb

16

要在依赖基类中查找名称,需要满足两个条件:

  • 必须非未限定的查找
  • 名称必须是相关的

这些规则在C++03中陈述的方式与未修订的C++98中所述的规则不同,其中符合第二点(使名称相关)就足以查找在依赖基类中声明的名称。

相关名称会在实例化时查找,非未限定查找将不会忽略依赖的基类。要查找在依赖基类中声明的名称,必须同时满足这两个条件,任何一个条件单独满足都不足够。为了满足这两个条件,可以使用各种构造。

this->p
class1::p

两个名字都是有依赖性的,第一个版本使用了类成员访问查找(class member access lookup),而第二个版本使用了限定名查找(qualified name lookup)


2

我在VC9中没有遇到编译错误。然而,这段代码存在几个问题:首先,按照当前的写法,它不需要成为一个模板类...但也许你只是为了简化问题?其次,基类应该有一个虚析构函数。

#include <iostream>

using namespace std;

class class0 {
public:
   virtual ~class0(){}

protected:
    char p;
public:
    char getChar();
};

class class1 : public class0 {
public:
    void printChar();
};

void class1::printChar(){
    cout << p << endl;//p was not declared in this scope
}

int main() {
   class1 c;
   c.printChar();
   return 1;
}

由于您正在学习模板,我建议在学习时不要混淆概念(继承和模板)。从一个简单的示例开始,比如这个...

#include <iostream>
#include <string>

using namespace std;

template <typename T>
T add(const T& a, const T& b) {
   return a + b;
}

int main() {
   int x = 5;
   int y = 5;

   int z = add(x, y);
   cout << z << endl;

   string s1("Hello, ");
   string s2("World!");

   string s3 = add(s1, s2);
   cout << s3 << endl;

   return 1;
}

上述代码中的重要概念是我们编写了一个函数,它知道如何将整数和字符串(以及许多其他类型)相加。


4
为什么基类应该有一个虚析构函数?模板通常用于实现参数多态性,而虚拟删除只对动态多态性有用(仅在进行多态删除时才有用)。 - Ben Voigt
1
Visual Studio 2008编译器在这种情况下已知无法正确实现模板查找规则。这就是为什么您看不到错误的原因。 - CB Bailey
@Ben Voigt,说得好,但是OP刚开始使用模板,我猜他们可能还没有涉及到这个。但看起来他们已经涉及到了继承,除非他特别想要编译时多态,否则最安全的方法是将基类析构函数声明为虚函数。 - dgnorton
@Charles Bailey,谢谢您提供的信息。我会去阅读相关资料。 - dgnorton
1
作为一般准则,如果基类没有其他虚函数,则不需要虚析构函数。这里就是这种情况。对于非多态的类进行多态删除非常罕见。 - Ben Voigt

0

非常抱歉重新提出这么老的问题,但我只是想添加一些有价值的东西,如果您的成员函数中有很多“p”。

class class1:public class0<T> {
public:
    using class0<T>::p; // add this line and in all member functions 
                        // will assume that "p" is the p from class0<T>
                        // very useful if you have hundreds of "p":s
                        // and don't want to replace every single one with "this->p"
    void printChar();
};

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