首页 > 解决方案 > static_assert : Derive 中的某个函数“必须”隐藏 Base 的类函数

问题描述

我面临一个奇怪的罕见问题,我想隐藏 Base 类的 function B::f1(int)

class B{
    public: void f1(int){}
    public: void f1(float){}
};
class C : public B{
    public: void f1(int){
        //static_assert(ASSERT_that_thisFunctionHidParentFunction,"");
        //some rare ugly hacky stuff
    }
    public: void f1(char){
        //static_assert(!ASSERT_that_thisFunctionHidParentFunction,"");
    }
};

一切正常;我只是担心可维护性。
我希望确保一个函数C::f1(int)总是隐藏B::f1(int)

如果B::f1(int)将来碰巧更改签名(例如更改为B::f1(int,int)),
我想要一些编译错误来通知程序员也C::f1(int)应该更改C::f1(int,int)为。

在现实世界中,我有问题的功能f1没有过载。
但是出于教育目的,如果也有过载,我想知道如何解决。(即可选)

我喜欢ASSERT_that_thisFunctionHidParentFunction我的代码注释中的可爱解决方案。
我不介意宏。

我的糟糕解决方案

我试图 typedef 强制编译错误,但在某些情况下它不会断言失败(MCVE-coliru),因为int它会自动转换为B::f1(float).

class B{
    public: void f1(int,int){}
    public: void f1(float){}
};
class C : public B{
    public: void f1(int){
        using XXX=decltype(std::declval<B>().f1(std::declval<int>()));
        //static_assert(ASSERT_that_thisFunctionHidParentFunction,"");
    }
    public: void f1(char){
        //static_assert(!ASSERT_that_thisFunctionHidParentFunction,"");
    }
};
int main() {
   return 0;
}

标签: c++functioninheritancec++17static-assert

解决方案


您可以检查函数指针是否不同。

使用 MSVC 2019 和 Clang 8,这对我有用,但是 GCC 将其拒绝为“不是常量表达式”,因此可能需要不同的东西或运行时断言。不确定哪个是正确的标准。

class B {
public:
    void f1(int) {}
    void f2(int) {}
    void f3(int) {}
    void f1(float) {}
};
class C : public B {
public:
    void f1(int) {}
    void f1(char) {}
    void f3(int) {}
};
static_assert(&B::f1 != &C::f1); // Won't work because of the overloading, can static_cast to get the overload you want
static_assert(static_cast<void(B:: *)(int)>(&B::f1) != static_cast<void(C:: *)(int)>(&C::f1));
static_assert(static_cast<void(B:: *)(int)>(&B::f2) != static_cast<void(C:: *)(int)>(&C::f2)); // static assertion failed
static_assert(&B::f3 != &C::f3); // passes, no static_cast as not overloaded

以这种方式隐藏成员函数时要非常小心,因为基类是公共的,而方法不是虚拟的。它可以很容易地进行转换,然后不调用派生函数。

C *c = ...;
B *b = c; // Implicit
b->f1(5); // Calls B::f1, not C::f1

如果可能,最好进行继承protectedprivate避免意外转换。


推荐阅读