我有一个带有堆成员“名称”的 A 类:
class A {
protected:
char *name;
public:
// Constructor
A() {
name = new char[10];
strcpy(name, "Undefined");
}
// Assignment Operator
virtual A &operator=(const A &rhs) {
if (this == &rhs) {
return *this;
}
delete [] name;
name = new char[10];
strcpy(name, rhs.name);
return *this;
}
// Destructor
virtual ~A() {
delete [] name;
}
};
我有带有附加变量“b”的子类 B:
class B : public A {
int b;
// Constructor
B():A(),b(0){}
// Assignment Operator
virtual B& operator=(const B& rhs) {
if (this == &rhs) {
return *this;
}
delete [] name;
name = new char[10];
strcpy(name, rhs.name);
b = rhs.b;
return *this;
}
// Destructor
virtual ~B() {
delete [] name;
}
};
我的子类 C 带有附加成员“char* name”:
class C : public A {
int* c;
// Constructor
C():A() {
c = new int[10];
for(int i = 0 ; i < 10 ; i++) {
c[i] = 0;
}
}
// Assignment Operator
virtual C& operator=(const C& rhs) {
if (this == &rhs) {
return *this;
}
delete [] name;
name = new char[10];
strcpy(name, rhs.name);
delete [] c;
c = new int[10];
for (int i = 0 ; i < 10 ; i++) {
c[i] = rhs.c[i];
}
return *this;
}
// Destructor
virtual ~C() {
delete [] name;
delete [] c;
}
};
我想知道这是否是为 B 和 C 实现运算符=和析构函数的正确方法。 有没有办法在B或C中调用A的operator=或析构函数,这样我就不用一遍又一遍地给所有成员写赋值了。
回答所问的问题,是的,派生类
operator=()
可以调用基类operator=()
。例如;
B& operator=(const B& rhs) {
A::operator=(rhs);
b = rhs.b;
return *this;
}
(与
C
类似)。
然而,这并不是一个特别好的方法。接下来,我将解决一些您没有询问过的对您的方法的担忧。
您的
operator=()
不一定是虚拟的。
最好根本不声明或定义
B::operator=()
。这样做允许 B::operator=()
隐式生成(例如由编译器),并且隐式生成的版本调用基类版本,并按值复制/分配所有成员。自行推出的唯一原因是隐式生成的 operator=()
不适合您的派生类。
另外,
if (this == &rhs)
中的A::operator=()
是不需要做的。相反,它可以定义为
A &operator=(const A &rhs) {
char *newname = new char [std::strlen(rhs.name)];
strcpy(newname, rhs.name);
delete [] name;
name = newname;
return *this;
}
除了避免
this == &rhs
测试(如果 A
有 operator&()
将会产生不同的行为)之外,这种方法也是安全的 - 如果 new
表达式抛出异常,则对象不会改变。
这样做的唯一缺点是,暂时会产生少量额外的内存使用(在
name
被释放并重新分配之前,rhs.name
、newname
和 name
都会消耗内存)。
使用这种方法,
C::operator=()
将被实现来调用A::operator=()
并分配/复制/释放c
。
此外,
B
和C
的析构函数通常不应释放A
的成员。当 B
和 C
被破坏时,A
的构造函数被隐式调用(因此您的方法将导致 A::name
被破坏两次,从而导致未定义的行为。
最后,您可以使用标准容器(
std::string
或std::vector<char>
),并完全避免手动内存分配(new
和delete
)。有关更多信息,请参阅“零C++规则”。