重写成员函数时可以继承已删除的重载吗?

问题描述 投票:0回答:2

这是我的问题的一个最小示例:

#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
的结构)。我找不到如何做到这一点。

c++ inheritance
2个回答
1
投票

您的

Bar::Print()
隐藏了
Base
中的重载。

我们需要将其他覆盖引入

Bar
,我们使用
using

    using Base::Print;

    void Print(double d) override
    {
        std::cout << "Bar: " << d << std::endl;
    }

现在尝试使用

Print(a);
的格式不正确。

仅通过更改 Base 实现无法实现这一


1
投票
如果您想保留

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 }

现场演示


PS:后来才知道有一种方法可以通过删除

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

© www.soinside.com 2019 - 2024. All rights reserved.