序曲:我已更新此问题以解决NicolBolas的建议。如果你是投票,请留下建设性的评论,谢谢。
我正在编写一个函数,它接受一个数字(uint
)或一个不是数字的标志。然后它继续使用给定的数字或-1
。
这是想法
struct Numeric {
virtual int to_int() const = 0;
};
struct NotANumber : Numeric {
int to_int () const {
return -1;
}
}
struct Number : Numeric {
const uint n;
Number (const uint n): n(n) {}
int to_int () const {
return n;
}
};
那么我的函数可以用作:
calculate_stuff(NotANumber());
calculate_stuff(Number(4));
我的问题是,是否可以将to_int
方法移到类之外,转换为重载函数的形式:
struct Numeric {};
struct NotANumber : Numeric {}
struct Number : Numeric {
const uint n;
Number (const uint n): n(n) {}
};
int Numeric_to_int (const NotANumber) {
return -1;
}
int Numeric_to_int (const Number n) {
return n.n;
}
这似乎不起作用。有可能解决这个问题吗?问题是重载是在编译时发生的,而重写是在运行时吗?
(我想我会针对这个具体问题使用std::optional
和value_or
,但我仍然想知道上述问题的答案。
编辑:抱歉,我应该澄清“不起作用”的含义:
int calculate_stuff (const Numeric n) {
std::cout << Numeric_to_int(n) << std::endl;
return 0;
}
这不会编译:{{1}}
答案 0 :(得分:1)
我的问题是,是否可以将
to_int
方法移出类之外,形成重载函数。
只有在您始终处理派生类型时,才使用重载的非成员函数是可行的选项。
如果您需要通过引用或指向基类类型的指针来使用该功能,那么使用重载的非成员函数不是一个可行的选择。在这种情况下,virtual
成员函数是正确的选择。
答案 1 :(得分:1)
int calculate_stuff (const Numeric n)
怎么会有效?你传入了一个基类。 按价值。编译器无法知道它曾经是什么派生类。实际上,由于您按值获取了基类,因此编译器知道 n
。
C ++不是Java;如果你按值传递某些东西,你可以复制(或移动到它)。如果你传递了一个派生类,causes slicing;您只复制基类数据。因此,该参数正是它所说的:动态类型为Numeric
的对象。正是这样,而不是它的派生类之一。
即使您使用了const Numeric &n
,也无济于事。编译器不知道它曾经是什么类型。你甚至无法使用dynamic_cast
将其转换回来,因为Numeric
不是多态类。
更好的方法是实际使用正确的variant
类(optional
实际上是专门的variant
)。
答案 2 :(得分:0)
您可以使用模板类和使用声明来执行此操作:
template<int v>
struct Numeric {};
using NotANumber = Numeric<-1>;
template<int N>
constexpr int Numeric_to_int (Numeric<N>) {
return N;
}
int main() {
static_assert(Numeric_to_int(NotANumber{}) == -1, "!");
static_assert(Numeric_to_int(Numeric<42>{}) == 42, "!");
}
另外,考虑使用std::integral_constant
用于同一目的
举个例子:
template<int v>
using Numeric = std::integral_constant<int, v>;