添加具有相同名称的方法后,继承的模板化方法不可见

时间:2019-01-23 10:32:32

标签: c++ templates inheritance pure-virtual

我有以下问题。类E覆盖了两种方法:一种来自抽象类D,该抽象类继承自模板类C<T>的特殊化,其中T = A。另一个直接来自C<A>。两者的名字相同。

现在,D应该可以访问这两种方法:doSomething(const A& a)因为它是从C继承的,而doSomething(const B& b)是因为D声明了它。

但是,以下代码无法编译,因为编译器只能从指向doSomething(const B&)的指针中识别方法D

#include <iostream>
#include <sstream>
using namespace std;

class A {
private:
    int a = 10;
public:
    inline std::string hello() const{
        std::stringstream ss;
        ss << a;
        return ss.str();
    }
};

class B {
private:
    int b = 20;
public:
    inline std::string hello() const{
        std::stringstream ss;
        ss << b;
        return ss.str();
    }
};

template <class T>
class C {
public:
    inline virtual bool doSomething(const T& t) {
     std::cout << "C is doing something with T" << t.hello() << std::endl;
     return true;
    }
};


class D : public C<A> {
public:
    virtual void doSomething(const B& b) = 0;
};

class E : public D {
public:
    inline bool doSomething(const A& a) override {
        std::cout << "E is doing something with A: " << a.hello() << std::endl;
        return true;
    }

    inline void doSomething(const B& b) override {
        std::cout << "E is doing somethign with B: " << b.hello() << std::endl;
    }
};


int main()
{
  A a;
  B b;
  D* d = new E();

  d->doSomething(b);
  d->doSomething(a); // compile error, does not recognize doSomething(const A&)

  delete d;
}

编译器显示以下错误:

In function ‘int main()’:
main.cpp:62:19: error: no matching function for call to ‘D::doSomething(A&)’
   d->doSomething(a); // compile error, does not recognize doSomething(const A&)
                   ^
main.cpp:39:18: note: candidate: virtual void D::doSomething(const B&)
     virtual void doSomething(const B& b) = 0;
                  ^
main.cpp:39:18: note:   no known conversion for argument 1 from ‘A’ to ‘const B&’

那是为什么?

2 个答案:

答案 0 :(得分:2)

之所以发生这种情况,是因为编译器不会自动将基类中的所有功能合并到要选择的重载功能集中。那就是当您调用d->doSomething(a);仅由D::doSomething(const B& b)组成的一组重载函数。为了解决这个问题,您需要将C<A>::doSomething;纳入D

 class D : public C<A> {
 public:
     using C<A>::doSomething;
     virtual void doSomething(const B& b) = 0;
 };

答案 1 :(得分:1)

要使基类函数在派生类中可见并被同名函数隐藏,应使用using指令(using C<A>::doSomething;)。

但是,我还想补充一点,当您delete d时,GCC 8.2报告代码中存在未定义的行为。这是因为类D具有非虚拟的析构函数。

warning: deleting object of abstract class type 'D' which has non-virtual destructor will cause undefined behavior [-Wdelete-non-virtual-dtor]
       delete d;

请参见demo here