动机,如果有帮助的话::我有一些结构成员函数,它们是径向基函数内核。在数值模拟中,它们被称为1e06 x 15 x 1e05次。对于许多函数调用,我都不希望依靠去虚拟化来内联虚拟函数。同样,结构(RBF内核)已经用作较大插值类的模板参数。
最小的工作例子
我有一个g()始终不变的函数,并且我想重用它,因此我将其打包在基类中。
该函数g()调用f()派生类中不同的函数。
我不想virtual在运行时使用函数来解析函数名称,因为这会产生额外的费用(我在代码中对其进行了度量,但会产生影响)。
这是示例:
#include <iostream>
struct A
{
double f() const { return 0; };
void g() const
{
std::cout << f() << std::endl;
}
};
struct B : private A
{
using A::g;
double f() const { return 1; };
};
struct C : private A
{
using A::g;
double f() const { return 2; };
};
int main()
{
B b;
C c;
b.g(); // Outputs 0 instead of 1
c.g(); // Outputs 0 instead of 2
}
Run Code Online (Sandbox Code Playgroud)
我希望名称解析机制能够弄清楚我想使用“ A :: g()”,但是然后返回到“ B”或“ C”来解析“ f()”函数。大概是这样的:“当我在编译时知道一个类型时,我将尝试首先解析该类型中的所有名称,然后从缺少某些对象的对象/父对象中进行名称查找,然后返回到我从中被调用的类型”。但是,似乎弄清楚了使用了“ A :: g()”,然后它位于“ A”中,只是选择了“ A :: f()”,即使实际调用“ g()”来自“ B”和“ C”。
可以使用虚函数解决此问题,但是我不理解,并且想知道在编译时知道类型时名称查找遵循父类的原因。
没有虚拟功能怎么办?
这是CRTP的标准任务。基类需要知道对象的静态类型是什么,然后将其自身强制转换为静态类型。
template<typename Derived>
struct A
{
void g() const
{
cout << static_cast<Derived const*>(this)->f() << endl;
}
};
struct B : A<B>
{
using A::g;
double f() const { return 1; };
};
Run Code Online (Sandbox Code Playgroud)
另外,回应您写的评论(也许这是您的真正问题?),
您能告诉我名称查找坚持基类的原因是什么,而不是一旦查找g()便返回到派生类?
因为类旨在用于面向对象的编程,而不是用于代码重用。有A需求的程序员必须能够理解他们的代码在做什么,这意味着子类不应能够从基类中任意重写功能。这就是virtual就是,真正做到:A给予其子类的权限覆盖特定成员。任何A没有为此选择的东西,他们都应该能够依靠。
在您的示例中考虑:如果B后来的作者添加了一个恰巧被称为的整数成员,该endl怎么办?那应该休息A吗?是否应该B关心所有的私有成员名称A?而且,如果的作者A想要添加成员变量,他们是否应该能够以不破坏某些子类的方式添加成员变量?(答案是“否”,“否”和“是”。)
| 归档时间: |
|
| 查看次数: |
87 次 |
| 最近记录: |