首页 > 解决方案 > 为什么成员函数名称查找留在父类中?

问题描述

动机,如果有帮助的话::我有结构成员函数,它们是径向基函数内核。在数值模拟中,它们被称为 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
}

我希望名称解析机制能够确定我想使用“A::g()”,然后返回“B”或“C”来解析“f()”函数。类似的东西:“当我在编译时知道一个类型时,我将尝试首先解析此类型中的所有名称,并从对象/父项中查找名称,缺少某些内容,然后返回我被调用的类型”。但是,它似乎发现使用了“A::g()”,然后它位于“A”中并只选择“A::f()”,即使对“g()”的实际调用来自“B”和“C”。

这可以使用虚函数来解决,但我不明白并且想知道在编译时已知类型时坚持父类的名称查找背后的原因

如果没有虚拟功能,我怎样才能让它工作?

标签: c++inheritance

解决方案


这是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; };
};

另外,回复您写的评论(这可能是您真正的问题?),

你能告诉我名称查找坚持基类的原因是什么,而不是在查找 g() 后返回派生类?

因为类旨在用于面向对象的编程,而不是用于代码重用。程序员A需要能够理解他们的代码在做什么,这意味着子类不应该能够任意覆盖基类的功能。实际上就是virtual这样:授予其子类覆盖该特定成员A的权限。任何没有选择加入的东西,他们都应该能够依赖。A

在您的示例中考虑:如果作者B后来添加了一个恰好被调用的整数成员endl怎么办?应该打破A吗?应该B关心所有私有成员的名字A吗?如果作者A想要添加一个成员变量,他们是否应该能够以一种不会破坏某些子类的方式这样做?(答案是“否”、“否”和“是”。)


推荐阅读