在c++中,我可以重置操作符的函数指针

In C++ can I reset the function pointer for an operator?

本文关键字:操作符 函数 指针 c++ 我可以      更新时间:2023-10-16

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

特别地,我想设置成员函数operator[]使用(或不使用)边界检查。我试了一下,没有运气:

这可能吗?如果有,有人能纠正语法吗?

in MyArrayClass.h:

class MyArrayClass {
public:
    bool CheckArrayBounds;
    float BoundsCheck(int i) {
        if (i<_size) 
            return _data[i]; 
        return TCpx(_INVALID); 
    }
    float NoBoundsCheck(int i) {
        return _data[i]; 
    }
    void UseBoundsCheck(bool State) {
        if (State) {
            float (operator[]) = &MyArrayClass::BoundsCheck;
        } else {
            float (operator[]) = &MyArrayClass::NoBoundsCheck;
        }
        CheckArrayBounds = State;
    }
    float operator[](int i) { return _data[i]; };
};

这不可能。从语义上讲,成员函数不是函数指针(尽管它们可以在底层以这种方式实现)。

您可以在operator[] ()中对State执行检查,或者使用代理对象

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

仍然可以检查操作符[]实现内部的状态。

也可以创建属性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 );

No.

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

遗憾的是,

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()。让你的类的用户决定他们是否需要检查

函数和成员函数实际上是常量或不可变的,并且不可能在运行时更改它们。然而,对于你想要做的事情,有一种半途而废的方法,而你在发布的代码中几乎已经实现了。

你所能做的就是定义一个指向成员函数的指针,然后在运行时根据你是否想要激活边界检查来改变指针的值。

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); }
};

这是我能想到的最接近你要求的方法了