CppCoreGuidelines C.138 通过 using 在派生类中重载基类的函数
28 December 2022
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)的情况