CppCoreGuidelines C.138 通过 using 在派生类重载基类的函数
28 December 2022
“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 B { public: virtual void operator()(int x) { std::cout << "B( " << x << " )" << std::endl; } virtual ~B() = default; }; template<class... Ts> struct Overloader : Ts... { using Ts::operator()...; // exposes operator() from every base void operator()() { std::cout << "Overloader()\n"; } }; int main() { Overloader<B> d; d(42); d(); }
B( 42 ) Overloader()
强化
诊断名字隐藏的情况