自定义C++类的漏洞问题

4

我需要帮助解决使用自定义的C++类来管理3D位置时出现的问题。以下是该类的相关代码:

  Punto operator+(Punto p){
    return Punto(this->x + p.x, this->y + p.y, this->z + p.z);
  }

  Punto operator+(Punto *p){
    return Punto(this->x + p->x, this->y + p->y, this->z + p->z);
  }

  Punto operator-(Punto p){
    return Punto(this->x - p.x, this->y - p.y, this->z - p.z);
  }

  Punto operator-(Punto *p){
    return Punto(this->x - p->x, this->y - p->y, this->z - p->z);
  }

  Punto *operator=(Punto p){
    this->x = p.x;
    this->y = p.y;
    this->z = p.z;
    return this;
  }

  Punto *operator=(Punto *p){
    this->x = p->x;
    this->y = p->y;
    this->z = p->z;
    return this;
  }

我在这里这样使用它:
p = fem->elementoFrontera[i]->nodo[0] - fem->elementoFrontera[i]->nodo[1];

其中nodo[i]是一个Punto*,它能够编译通过,但当我尝试执行以下操作时:

p = fem->elementoFrontera[i]->nodo[0] + fem->elementoFrontera[i]->nodo[1];

编译器报错:
在成员函数`void mdTOT::pintarElementosFrontera()':中, 错误: 无效的操作数类型 Punto*'和Punto*'不能进行二进制运算符'


我们能获取构造函数和.h代码吗? - Jim Wallace
Punto(double _x, double _y, double _z){ x = _x; y = _y; z = _z; } Punto(Punto *v){ x = v->x; y = v->y; z = v->z; } Punto(const Punto &v){ x = v.x; y = v.y; z = v.z; } - Luis Yanes
这种混乱很好地说明了应该避免运算符重载... - ojrac
2个回答

5
第一个能编译通过,因为在C/C++中可以进行指针相减,但不能进行指针相加。但无论如何,它都不能满足你的需求 - 它不使用你重载的运算符。由于你的运算符是在类中定义的,你需要对类实例进行操作,而不是对指针进行操作。因此,将其更改为以下内容:
Punto p = *(fem->elementoFrontera[i]->nodo[0]) + *(fem->elementoFrontera[i]->nodo[1]);

另外,你应该在操作符定义中使用类引用,而不是值。例如:

 Punto& operator+(const Punto& p) {

编辑。为了简化代码,您可以创建一个访问器函数,如下所示:

const Punto& NodoRef(int i, int j) {
  return *(fem->elementoFronteria[i]->Nodo[j]);
}

然后你的代码就会变得像这样干净:
p = NodoRef(i,0) + NodoRef(i,1);

NodoRef 可以在你的 fem 类中定义,也可以在外部定义。只需确保在使用 NodoRef 的范围内 fem 对象是活着的。

有没有任何方法可以让它看起来更漂亮一些?我的意思是,每次操作都需要引用代码,这很丑陋,不是吗? - Luis Yanes
这是一个品味问题。我更喜欢显式的代码,不喜欢任何隐藏的魔法。如果我有一个指针,在执行任何操作之前,我知道需要对其进行解引用。 - Igor Krivokon
从技术上讲,您可以使用两个参数声明指向Punto的指针的类外operator+,但它需要返回一个对象。因此,这很丑陋:+运算符不返回与操作数相同的类型。我不建议这样做。 - Igor Krivokon
关于如何使它更漂亮:我会创建一个访问函数,返回一个指向Punto的const引用。让我更新答案... - Igor Krivokon

0
第一个版本可以工作,因为在这种情况下"-"执行普通指针算术运算,没有使用任何重载运算符。在普通指针上未定义"+",因此会出现错误。要使用重载的版本,请解引用第一个指针:
p = *fem->elementoFrontera[i]->nodo[0] - fem->elementoFrontera[i]->nodo[1];

解引用两个指针也应该可以工作,因为你有两种类型的重载,但在这种情况下,你应该改变你的运算符定义来使用const引用:

Punto operator+(const Punto &p){
   ...
}

这样,每次使用“+”时,对象就不会被复制。

基本上,您想要做的是这样的:

const Punto operator+(Punto *left, Punto *right); // not allowed

但是重载一个接受两个指针并以适当的方式将它们相加的自由函数operator+是行不通的,因为至少其中一个参数需要是枚举或类类型。原始类型没有运算符重载,而指针被视为这样的类型。


我也有同感,到处都使用解引用真的很难看,有什么建议可以让它看起来更简洁? - Luis Yanes
你能否在elementoFrontera向量中存储 Punto 对象而不是指向它们的指针?这样“+”符号就可以按预期工作了... - sth
这个想法是让它指向其他地方,那里保存了Punto对象。 - Luis Yanes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接