我可以通过重载来复制继承吗?

时间:2016-08-10 16:55:30

标签: c++

序曲:我已更新此问题以解决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::optionalvalue_or,但我仍然想知道上述问题的答案。

编辑:抱歉,我应该澄清“不起作用”的含义:

int calculate_stuff (const Numeric n) {
    std::cout << Numeric_to_int(n) << std::endl;
    return 0;
}

这不会编译:{{1​​}}

3 个答案:

答案 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>;