我想编写一组 D_I 类(又名 I=1,2,...只是我的意思是“_I”是类专有名称,而不是整数)来处理一些(例如 bool 值)操作F 对于所有类别具有相同的含义。但我也想对这些类的对象的“总和”进行操作,该组的不同类可能会“添加”在一起。上述对此类对象求和的操作依赖于添加对象的相应操作。
这就是为什么我要创建公共(public)基类 B 来处理“求和”操作:
class B
{public:
B (): LEFT(NULL), RIGHT(NULL) {};
B (const SpBrd& S);
B (const B& A, const B B);
~B ();
{if (LEFT != NULL) delete LEFT; // NULL if it is default B or D_I
if (RIGHT != NULL) delete RIGHT; // NULL if it is default B or D_I
}
B operator + (const B& S) const;
bool F(const Point& P) const;
{bool b = aF(P);
if (LEFT != NULL) b = b && LEFT->F(P); // this is how F depends
if (RIGHT != NULL) b = b && RIGHT->F(P); // of added classes
}
protected:
virtual bool aF(const Point& P) const {return true;}; // Default!
B* LEFT; // Pointer to left operand of "sum"
B* RIGHT; // Pointer to right operand of "sum"
// (since it might point to D_i class too as well)
};
这样派生类 D 就很容易编写,因为它应该只处理它的构造函数和 aF:
class D_I: public B
{public:
D() {...};
protected:
virtual bool aF (const Point& P) const
{// return something here
}
};
问题是:如何编写 B 类的运算符 + 和复制构造函数:
B:B (const B& S)
{if (S.LEFT != NULL) LEFT = new B (S.LEFT)
if (S.RIGHT != NULL) RIGHT = new B (S.RIGHT)
};
B B:operator + (const B& S) const
{SpBrd S;
S.LEFT = new B (*this);
S.RIGHT = new B (S);
};
不会产生正确的结果,因为如果“operator +”或“S.LEFT”中存在“this”、“S”,则“new B ...”应替换为相应的“new D_I ...”复制构造函数中的“S.RIGHT”并不完全指的是 B 类的对象,而是指的是 D_I 类之一的对象。
所以,我找不到一种方法让 B::operator+ 知道 sum 的来源类型,因为可能存在大量 D_I 并且它们会不时添加。我应该怎么做才能正确地写出这一切?
我无法为所有 (D_I,D_J) 对编写 D_I 运算符+ (D_J) 和 D_I::D_I(const D_J) 的部分,这不公平!
(这代表空间中的边界(表面)之类的东西。函数 F 代表在边界内部——即检查该点是否在空间体内。但是我想要操作的边界内部的物体可能是交集(其他两个边界内的空间物体。示例:两个球体边界(内部区域和外部区域)的交集产生球壳,又名 3D 环;可能还想查看半径为 R 且立体角为 10*10 的球体边界的交集绕极点的度数等。)
最佳答案
你的问题很令人困惑,我在这里感到很匆忙,但我会这么说。
通常,运算符在类外部声明为非成员函数,并使用成员函数来实现其目标。这样一来,运算符的两个参数都可以平等地参与重载决策。
在本例中,您似乎正在尝试创建某种基于 C++ 运算符的解析树。在这种情况下,您可能正在寻找这样的代码:
const B operator +(const B &a, const B &b)
{
return B(a, b);
}
请注意,即使从 B 派生的东西是任一操作数,这也会起作用。如果我对你所做的事情是正确的,你可能会有一个特殊的节点类型,用于将两个东西添加到彼此,并且运算符 + 可以返回它。
现在我看到了您的澄清版本,这是一个不同的答案。
首先,我质疑您以这种方式使用运算符 + 。运算符重载通常会给使用您的类的人带来意外,并且除非您对运算符 + 的使用行为与人们期望的运算符 + 的一般行为非常相似,否则它将导致更多它解决的问题。
但是您的实际问题似乎围绕着创建未知类型对象的拷贝而无需大量重复代码。当我看到重复的代码时,我倾向于想到模板。这是一些示例代码,可能比您需要的使用模板的代码复杂一点,我认为可以解决您的问题。
#include <memory>
#include <iostream>
template <class BaseType, class DerivedType>
class Cloneable {
public:
virtual ~Cloneable() {}
::std::auto_ptr<DerivedType> clone() const {
return ::std::auto_ptr<DerivedType>(static_cast<DerivedType *>(i_clone()));
}
protected:
virtual BaseType *i_clone() const {
return new DerivedType(dynamic_cast<const DerivedType &>(*this));
}
};
class A : public Cloneable<A, A> {
public:
A() {}
A(const A &b) {
const void * const voidb = &b;
const void * const voidme = this;
::std::cerr << "Creating a copy of the A at " << voidb << " and this new copy will reside at " << voidme << "\n";
};
virtual ~A() {
const void * const voidme = this;
::std::cerr << "Destroying the A at " << voidme << "\n";
}
};
template <class Derived>
class B : public A, public Cloneable<A, Derived> {
public:
B() {}
B(const B &b) {
const void * const voidb = &b;
const void * const voidme = this;
::std::cerr << "Creating a copy of the B at " << voidb << " and this new copy will reside at " << voidme << "\n";
};
virtual ~B() {
const void * const voidme = this;
::std::cerr << "Destroying the B at " << voidme << "\n";
}
// Make sure clone can be mentioned in derived classes with no ambiguity
using Cloneable<A, Derived>::clone;
protected:
// Force dominance rules to choose the correct i_clone virtual function.
virtual A *i_clone() const {
return Cloneable<A, Derived>::i_clone();
}
};
class C : public B<C> {
public:
C() {}
C(const C &b) {
const void * const voidb = &b;
const void * const voidme = this;
::std::cerr << "Creating a copy of the C at " << voidb << " and this new copy will reside at " << voidme << "\n";
};
virtual ~C() {
const void * const voidme = this;
::std::cerr << "Destroying the C at " << voidme << "\n";
}
};
class D : public B<D> {
public:
D() {}
D(const D &b) {
const void * const voidb = &b;
const void * const voidme = this;
::std::cerr << "Creating a copy of the D at " << voidb << " and this new copy will reside at " << voidme << "\n";
};
virtual ~D() {
const void * const voidme = this;
::std::cerr << "Destroying the D at " << voidme << "\n";
}
};
int main(int argc, const char *argv[])
{
C c;
D d;
::std::auto_ptr<A> cptr(c.clone());
::std::auto_ptr<A> dptr(d.clone());
cptr = dptr->clone();
return 0;
}
我创建了 i_clone 和clone 方法,以便每个类最终都会得到一个返回指向该类自己类型的指针的clone 版本。我还必须在模板类 B 中使用 using
声明,以确保在派生类中调用哪个克隆不会出现歧义。
请注意类 C 和 D 如何不包含与创建自身克隆相关的重复代码。
虽然当时 a 并不知道,但这似乎是 The Curiously Recurring Template 的又一次重新发明。适用于 polymorphic copy construction 的习语.
关于C++ 运算符代码继承出现问题 : am I require to copy same code for all derived classes?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2058328/