问题描述
我想隐藏基类的虚函数,并引入一个具有相同名称和相同签名的新虚函数,但返回类型除外。
类似于:
using Microsoft.AspNetCore.nodeservices;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace ConvertHighchart.Controllers
{
[ApiController]
[Route("[controller]")]
public class runNodeScriptController : ControllerBase
{
private readonly Inodeservices _nodeservices;
public runNodeScriptController(Inodeservices nodeservices)
{
_nodeservices = nodeservices;
}
[HttpPost]
public async Task<IActionResult> Post()
{
var result = "";
try
{
result = await _nodeservices.InvokeExportAsync<string>("test_nodejs_script","generateHighChart","abc");
}
catch (System.Exception ex)
{
}
return Ok(result);
}
}
}
我希望它的行为方式如下:
struct A {
virtual int f() = 0; // Newly introduced method: A::f.
};
struct B: public A {
int f() final { return 1; } // Overriding A::f.
};
struct C: public B {
virtual double f() = 0; // Newly introduced method C::f. It shadows A::f
};
struct D: public C {
double f() final { return 2.0; } // Overriding C::f.
};
有可能实现吗?
任何版本的 C++ 标准都可以。
解决方法
如果不改变函数签名(返回类型不是它的一部分),重载是不可能的。但是由于默认函数参数,我们可以有不同的签名,但仍然使用相同数量的参数调用。使用 C++20 的 std::type_identity
之类的东西(尽管很容易在任何标准中实现),一旦可以编写
struct A {
virtual int f(std::type_identity<int> = {}) = 0;
};
struct B: public A {
int f(std::type_identity<int> = {}) final { return 1; }
};
struct C: public B {
virtual double f(std::type_identity<double> = {}) = 0;
};
struct D: public C {
double f(std::type_identity<double> = {}) final { return 2.0; }
};
现在每个重载都标有其返回类型,从而赋予每个重载不同的签名。但是默认参数 {}
可以通过 f()
调用它们。并且由于名称隐藏,空参数列表的重载集没有冲突。
通过这些修改,your set of assertions now passes。
,如果不让B
直接继承E
,而是引入同时继承B
和D
的{{1}},你可以有不同的 f()
并用 static_cast
消除它们之间的歧义。
struct A {
virtual int f() = 0; // Newly introduced method: A::f.
};
struct B: public A {
int f() override final { return 1; } // Overriding A::f.
};
struct C {
virtual double f() = 0; // Newly introduced method C::f
};
struct D: public C {
double f() override final { return 2.0; } // Overriding C::f.
};
struct E : public B,public D { // inherit from both B and D
};
int main() {
E foo;
std::cout << static_cast<A&>(foo).f() << '\n'; // 1
std::cout << static_cast<B&>(foo).f() << '\n'; // 1
std::cout << static_cast<C&>(foo).f() << '\n'; // 2
std::cout << static_cast<D&>(foo).f() << '\n'; // 2
}