这是我的问题的一个最小示例:
#include <iostream>
struct Base
{
virtual void Print(double d) = 0;
void Print(int a) = delete;
};
struct Bar : public Base
{
void Print(double d)
{
std::cout << "Bar: " << d << std::endl;
}
};
int main()
{
Bar b;
int a = 1;
b.Print(a);
}
我希望
b.Print(a)
生成编译器错误。如果我在 void Print(int a) = delete;
中添加 Bar
我就可以做到这一点,但我希望 Base
结构来处理这个问题(在我的实际用例中,我有多个继承自 Base
的结构)。我找不到如何做到这一点。
您的
Bar::Print()
隐藏了 Base
中的重载。
我们需要将其他覆盖引入
Bar
,我们使用using
:
using Base::Print;
void Print(double d) override
{
std::cout << "Bar: " << d << std::endl;
}
现在尝试使用
Print(a);
的格式不正确。
仅通过更改 Base
实现无法实现这一
。
virtual void Print(double d) = 0;
,那么您无法通过
Bar
中采取的任何措施来阻止
Base
中发生的隐式转换。当您调用
b.Print(1)
时,namelookup 会找到
Bar::Print
并停止。重载分辨率则仅考虑
Bar::Print
。通常,防止隐式转换的一种方法是编写函数模板并依赖参数推导。例如
void foo(auto x)
总是会推导出
x
的“正确”类型。虽然你不能将虚拟方法作为模板。如果您可以更改
Print
的签名,您可以将“避免转换模板”放置在其他地方。这与 PaulMcKenzie 在评论中的建议类似:
#include <type_traits>
#include <iostream>
struct Double {
template <typename T, typename = std::enable_if_t<std::is_same_v<T,double>>>
Double(T value) : value(value) {}
double value;
};
struct Base
{
virtual void Print(Double d) = 0;
void Print(int a) = delete;
};
struct Bar : public Base
{
void Print(Double d) override
{
std::cout << "Bar: " << d.value << std::endl;
}
};
int main()
{
Bar b;
int a = 1;
double c = 42.0;
b.Print(c); // OK
b.Print(a); // ERROR
}
Base
中的方法来报错。如果您可以放弃
void Print(double)
上的虚拟(而是使用不同的方法虚拟),那么这是可行的:
#include <iostream>
struct Base
{
void Print(double d) { doPrint(d); }
void Print(int a) = delete;
private:
virtual void doPrint(double d) = 0;
};
struct Bar : public Base
{
private:
void doPrint(double d) override
{
std::cout << "Bar: " << d << std::endl;
}
};
int main()
{
Bar b;
int a = 1;
b.Print(4);
}
派生类不是重写 Print
,而是重写
doPrint
,它可以是
private
。