在C ++中我可以重置操作符的函数指针吗?
特别是我想设置成员函数operator []来使用(或不使用)边界检查。我试了这个没有运气:
这甚至可能吗?如果是这样,任何人都可以更正语法吗?
在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]; };
};
答案 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); }
};
这是我能想到的最接近你要求的方式。