在C ++中我可以重置操作符的函数指针吗?

时间:2011-07-27 21:26:51

标签: c++ pointers overloading operator-keyword member

5 个答案:

答案 0 :(得分:6)

这是不可能的。从语义上讲,成员函数不是函数指针(尽管它们可以在引擎盖下实现)。

您可以对State内的operator[] ()执行检查,或使用代理对象。

答案 1 :(得分:2)

您无法在运行时更改特定对象实例的运算符,因为成员函数与对象属性分开存储,并且对于所有对象实例都是相同的。它们存储在写保护的内存段中。或者甚至可以由编译器内联。

仍然可以检查operator []实现中的状态。

您还可以创建属性at并替换运算符。

class MyArrayClass {
public:
    float (MyArrayClass::*at)(int i);
    float BoundsCheck(int i);
    float NoBoundsCheck(int i); {
    void UseBoundsCheck(bool State) {
        at = (State)? &MyArrayClass::BoundsCheck : &MyArrayClass::NoBoundsCheck;
    }
};

用法:

MyArrayClass a;
a.at( 1 );

答案 2 :(得分:1)

没有

方法(以及只是方法/函数的语法糖的运算符)是在编译时定义的,而不是运行时。

答案 3 :(得分:1)

不幸的是,

C ++并不适合这种语言。你需要一个更强大的类型系统。

请注意,即使你可以,你可能会慢下来你的程序:整数比较比函数通过指针调用要贵得多。特别是因为你的CPU可以分支预测:它将开始运行代码,好像它通过检查一样,如果它最终失败,它可以抛弃它正在做的事情。

但请注意您的编译器很聪明。例如,如果我们有这个:

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <vector>

void process(std::vector<int>& data)
{
    for (unsigned i = 0; i < data.size(); ++i)
    {
        int v = data.at(i);
        std::cout << v << std::endl;
    }
}

int main()
{
    try
    {
        std::vector<int> data;
        std::generate_n(std::back_inserter(data), std::rand() + 1, std::rand);

        process(data);
    }
    catch (...)
    {
        std::cerr << "nope.avi" << std::endl;
    }
}

如果我们使用g++ -O3进行编译,则无边界检查代码。实际上,编译器推断出at()内的检查永远不会通过(然后抛出),因此它会剥离该代码。因此,您可以保留检查边界,您的编译器仍然可以将其剥离。但请注意,任何更复杂的情况都可能使编译器难以证明,因此您需要付费。

这些是您可以通过更具表现力的类型系统保证的优化,但编译器无论如何都可以执行它们。我不知道MSVC;它往往不那么聪明,但你可以检查。

您最好的选择是转到std::vector<>路线:提供未经检查的operator[]和已选中的at()。让班级用户决定是否需要支票。

答案 4 :(得分:0)

函数和成员函数实际上是不可变的,并且不可能在运行时更改它们。但是,对于你想要做的事情,有一种中途的房子,你几乎就在你发布的代码中。

您可以做的是定义指向成员函数的指针,然后在运行时根据您是否要激活边界检查来更改指针值。

class MyArrayClass {
public:
    typedef float (MyArrayClass::*AccessFn)(int i);
    AccessFn Access;
    bool CheckArrayBounds;

    float BoundsCheck(int i) {
        if (i<_size)
            return _data[i];
        return TCpx(_INVALID);
    }
    float NoBoundsCheck(int i) {
        return _data[i];
    }

    MyArrayClass() { UseBoundsCheck(false); }

    void UseBoundsCheck(bool State) {
        if (State) {
            Access = &MyArrayClass::BoundsCheck;
        } else {
            Access = &MyArrayClass::NoBoundsCheck;
        }
        CheckArrayBounds = State;
    }
    float operator[](int i) { return (this->*Access)(i); }
};

这是我能想到的最接近你要求的方式。