28 December 2022

C++ 核心指南目录

C.138: Create an overload set for a derived class and its bases with using

理由

不使用 using 的话,派生类的成员函数会覆盖从基类继承来的所有重载函数。

例子

#include <iostream>
class B {
public:
    virtual int f(int i) { std::cout << "f(int): "; return i; }
    virtual double f(double d) { std::cout << "f(double): "; return d; }
    virtual ~B() = default;
};

class D: public B {
public:
    int f(int i) override { std::cout << "f(int): "; return i + 1; }
};

int main()
{
    D d;
    std::cout << d.f(2) << '\n';   // prints "f(int): 3"
    std::cout << d.f(2.3) << '\n'; // prints "f(int): 3"
}
f(int): 3
f(int): 3

例子

#include <iostream>
class B {
public:
    virtual int f(int i) { std::cout << "f(int): "; return i; }
    virtual double f(double d) { std::cout << "f(double): "; return d; }
    virtual ~B() = default;
};
class D: public B {
public:
    int f(int i) override { std::cout << "f(int): "; return i + 1; }
    using B::f; // exposes f(double)
};
int main()
{
    D d;
    std::cout << d.f(2) << '\n';   // prints "f(int): 3"
    std::cout << d.f(2.3) << '\n'; // prints "f(double): 3"
}
f(int): 3
f(double): 2.3

注意

这个问题会影响到虚的以及非虚的成员函数。

对于变参数模板类,C++17提供了一个带可变参数形式的 using 声明:

#include <iostream>
class B1 {
public:
    virtual void operator()(int x) {
        std::cout << "B1( " << x << " )" << std::endl;
    }
    virtual ~B1() = default;
};

class B2 {
public:
    virtual void operator()(double x) {
        std::cout << "B2( " << x << " )" << std::endl;
    }
    virtual ~B2() = default;
};

template<class... Ts>
struct Overloader : Ts... {
    using Ts::operator()...; // exposes operator() from every base
    void operator()() { std::cout << "Overloader()\n"; }
};

int main()
{
    Overloader<B1, B2> d;
    d(42);
    d(42.1);
    d();
}
B1( 42 )
B2( 42.1 )
Overloader()

强化

诊断名字覆盖(name hiding)的情况