我面临一个奇怪的罕见问题,我想隐藏基类的函数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;
}
答案 0 :(得分:1)
您可以检查函数指针是否不同。
在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
如果可能的话,最好进行继承protected
或private
以避免意外转换。
答案 1 :(得分:0)
按照我对您问题的理解,似乎您想确保几个实现类符合某个非虚拟概念。
template <typename Candidate>
struct ShipConcept
{
constexpr ShipConcept()
{
using ProtoFoo = void (Candidate::*)(int);
(void)static_cast<ProtoFoo>(&Candidate::foo);
// Other tests ...
}
};
struct Ship_A
: private ShipConcept<Ship_A>
{
Ship_A()
{
}
void foo(int, int);
void foo(float);
void foo(int); // (1)
};
如果第(1)行不存在,则会出现编译时错误。