重载分配运算符和上行



我想知道在处理继承和向上转换时,我应该如何(或者我可以吗?这有意义吗?(重载赋值运算符?假设我们有基类和派生类(继承自基类(。如果我有类似的东西:

/// supose we have one overloaded assignment operator in Base like Base& operator=(const Base&) and 
///one in Derived like Derived& operator=(const Derived&)...
Base* a, *b;
Derived c,d;
a = &c;
b = &d;
*a = *b  /// this will call the function in Base

如果这调用了Base函数,为什么我要重载"="在派生?Derived中的重载赋值运算符是否只有在直接处理对象时才需要,而不是向上转换(指针(?

以下是一些有望帮助您的代码。

Derived不拥有动态资源
Base类拥有动态资源,因此我们需要遵循规则3(应该是5,但为了简洁起见,保持为3(。我使用了复制/交换习惯用法。

然后,我从CCD_ 4导出CCD_ 3。它不包含动态资源,所以我遵循规则0,不提供自定义的复制构造函数、析构函数、赋值运算符、移动构造函数或移动赋值。

您可以从输出中看到,Derived对象的Base部分能够很好地深度复制它们,而仅Derived部分可以很好地进行浅层复制。最终的输出会泄漏内存,但我选择这样做是为了演示使用指向Base的指针进行实际覆盖。

#include <iostream>
class Base {
private:
int* m = nullptr;
public:
Base() = default;
Base(int v) : m(new int(v)) {}
Base(const Base& other) : m(new int(*(other.m))) {}
virtual ~Base() {
delete m;
m = nullptr;
}
Base& operator=(Base other) {
swap(*this, other);
return *this;
}
friend void swap(Base& lhs, Base& rhs) {
using std::swap;
swap(lhs.m, rhs.m);
}
virtual void print() const {
std::cout << "Address: " << m << "nValue: " << *m << 'n';
}
};
class Derived : public Base {
private:
double x = 0.0;
public:
Derived() = default;
Derived(double v) : Base(), x(v) {}
Derived(int i, double v) : Base(i), x(v) {}
void print() const override {
std::cout << "Address: " << &x << "nValue: " << x << 'n';
Base::print();
}
};
int main() {
std::cout << "An";
Base* a = new Derived(5, 3.14);
a->print();
std::cout << "nBn";
Derived b = *(dynamic_cast<Derived*>(a));  // Copy ctor
b.print();
std::cout << "nCn";
Derived c;
c = b;
c.print();
std::cout << "nReplace A (This leaks)n";
a = new Derived(7, 9.81);
a->print();
}

输出:

A
Address: 0x21712d0
Value: 3.14
Address: 0x21712e0
Value: 5
B
Address: 0x7ffdd62964c8
Value: 3.14
Address: 0x2171300
Value: 5
C
Address: 0x7ffdd62964b0
Value: 3.14
Address: 0x2171320
Value: 5
Replace A (This leaks)
Address: 0x2171350
Value: 9.81
Address: 0x2171360
Value: 7

Derived拥有动态资源
现在,Derived有自己的动态需要管理。因此,我遵循规则3,并提供一个复制构造函数、析构函数和赋值运算符重载。您会注意到赋值操作符看起来与Base版本完全相同;这是故意的。

这是因为我使用了复制/交换习惯用法。因此,在Derived的swap()函数中,我添加了一个步骤,其中它交换Base部分,然后交换Derived部分。我通过动态转换调用Baseswap()函数来实现这一点。

我们可以再次观察到,对于每个动态分配的部分,所有对象都有自己的内存。

#include <iostream>
class Base {
private:
int* m = nullptr;
public:
Base() = default;
Base(int v) : m(new int(v)) {}
Base(const Base& other) : m(new int(*(other.m))) {}
virtual ~Base() {
delete m;
m = nullptr;
}
Base& operator=(Base other) {
swap(*this, other);
return *this;
}
friend void swap(Base& lhs, Base& rhs) {
using std::swap;
swap(lhs.m, rhs.m);
}
virtual void print() const {
std::cout << "Address: " << m << "nValue: " << *m << 'n';
}
};
class Derived : public Base {
private:
double* x = nullptr;
public:
Derived() = default;
Derived(double v) : Base(), x(new double(v)) {}
Derived(int i, double v) : Base(i), x(new double(v)) {}
Derived(const Derived& other) : Base(other), x(new double(*(other.x))) {}
~Derived() {
delete x;
x = nullptr;
}
Derived& operator=(Derived other) {
swap(*this, other);
return *this;
}
friend void swap(Derived& lhs, Derived& rhs) {
using std::swap;
swap(dynamic_cast<Base&>(lhs), dynamic_cast<Base&>(rhs));
swap(lhs.x, rhs.x);
}
void print() const override {
std::cout << "Address: " << &x << "nValue: " << *x << 'n';
Base::print();
}
};
int main() {
std::cout << "An";
Base* a = new Derived(5, 3.14);
a->print();
std::cout << "nBn";
Derived b = *(dynamic_cast<Derived*>(a));  // Copy ctor
b.print();
std::cout << "nCn";
Derived c;
c = b;
c.print();
std::cout << "nReplace A (This leaks)n";
a = new Derived(7, 9.81);
a->print();
}

输出:

A
Address: 0x14812d0
Value: 3.14
Address: 0x14812e0
Value: 5
B
Address: 0x7fffe89e8d68
Value: 3.14
Address: 0x1481320
Value: 5
C
Address: 0x7fffe89e8d50
Value: 3.14
Address: 0x1481360
Value: 5
Replace A (This leaks)
Address: 0x14813b0
Value: 9.81
Address: 0x14813c0
Value: 7

这个例子的输出有助于澄清您的问题吗?您可以始终覆盖派生类中的operator=,如下所示:

#include <cstdio>
struct Base{
virtual ~Base() = default;
virtual void operator=(const Base&) {
std::printf("Base::=n");
}
};
struct Derived: public Base {
void operator=(const Derived&) {
std::printf("Derived::=n");
}
void operator=(const Base&) override{
std::printf("Derived::= Basen");
}
};

int main() {
Base* a, *b;
Derived c,d;
a = &c;
b = &d;
*a = *b; //Dispatches the call to the derived class =
Base base;
Derived derived;
derived = base; //Usual case now after operator=(const Base&) in Derived
c = d; //Usual case
Base base1, base2;
base1 = base2; //Usual case
a = &base1;
b = &base2;
*a = *b; //Usual case
}

输出:

Derived::= Base
Derived::= Base
Derived::=
Base::=
Base::=

相关内容

  • 没有找到相关文章

最新更新