添加同名方法后继承的模板化方法不可见

inherited templated method not visible after method with same name is added

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

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

但是,下面的代码编译不通过,因为编译器只从指向D

的指针识别方法doSomething(const B&)
#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&’

这是为什么?

发生这种情况是因为编译器不会自动将所有函数从基 class 合并到重载函数集到 select。那就是调用 d->doSomething(a); 时考虑的重载函数集仅由 D::doSomething(const B& b) 组成。为了解决这个问题,您需要将 C<A>::doSomething; 带入 D class

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

要使基 class 函数在被同名函数隐藏的派生 class 中可见,您应该使用 using 指令(using C<A>::doSomething;).

但是,我还想补充一点,当您 delete d 时,GCC 8.2 报告代码中存在未定义的行为。这是因为 class 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