C++学习笔记10-继承和动态内存分配,易错点总结

动态内存分配:

①派生类不使用new

Q:是否需要为派生类重新定义复制构造函数,复制运算符,析构函数?
A:不需要,子类中默认的复制构造函数,复制赋值运算符,析构函数就能完成所有的工作,虽然是浅层
复制,但是由于子类中没有申请动态内存,子类默认的复制构造函数,复制赋值运算符,析构函数都将
自动调用父类的复制构造函数,复制赋值运算符,析构函数,而父类的这些成员都是深复制的即可

②派生类使用new

Q:是否需要为派生类重新定义复制构造函数,复制运算符,析构函数?
A:需要!!

(Ⅰ)如何定义派生类复制构造函数

初始化列表显式调用基类的复制构造函数,并执行派生类新增数据的深度复制

Base::Base(const Base & o)
{
	str = new char[std::strlen(o.str)+1];
	std::strcpy(str,o.str);
}
Sub::Sub(const Sub & o) : Base(o)//显式调用基类的复制构造函数
{	下面是派生类成员的深度复制
	sub_str = new char[std::strlen(o.sub_str)+1];
	std::strcpy(sub_str,o.sub_str);
}

假设sub_str是派生类的新增的指针成员,str是基类的指针成员,子类的复制构造函数显式调用父类的
复制构造函数,对派生类的成员执行深度复制
即可

(Ⅱ)如何定义派生类复制赋值运算符

Base & Base::operator=(const Base & o)
{
	if(this!=&o)
	{
		delete[] str;
		str = new char[std::strlen(o.str)+1];
		std::strcpy(str,o.str);
	}
	return *this;
}
Sub & Sub::operator=(const Sub & o)
{
	if(this==&o)
	{
		delete[] sub_str;
		/*#1*/Base::operator=(o);显式使用基类的复制赋值运算符,完成基类成员的深度复制,*this是隐藏调用者
		/*#2*/或者这样this->Base::operator=(o);
		/*#3*/*this = o;绝对不能这样做,因为隐式调用了子类的复制赋值运算符,无限递归!!!
		sub_str = new char[std::strlen(o.sub_str)+1];
		std::strcpy(sub_str,o.sub_str);
	}
	return *this;
}

#1和#2选其一就行,绝对不能选#3的代码

(Ⅲ)如何定义派生类析构函数

在析构函数里面delete派生类里面的动态内存即可,然后派生类的析构函数会自动调用基类的析构函数
,一般来说,基类的析构函数只要也有delete基类的动态内存,就没有任何问题了
但是要注意:和构造函数的调用顺序不同,析构函数是先调用派生类的,再调用基类的析构函数!!

Base::~Base()
{
	delete[] str;
}
Sub::~Sub()
{
	delete[] sub_str;
	隐式执行基类析构函数
}

③析构多继承派生类

(Ⅰ)非虚继承

#include <iostream>

using namespace std;
class Base
{
private:
    int a;
public:
    Base(int c = 0) { a = c; cout << "using Base::Base" << endl; }
    virtual void f() { cout << "using Base::f" << endl; }
    virtual ~Base() { cout << "using Base destructor." << endl; }
};
class Mid_1 :public Base
{
private:
    int a;
public:
    Mid_1(int _a = 1, int b = 0) :
        Base(b), a(_a)
    {
        cout << "using Mid_1::Mid_1" << endl;
    }

    ~Mid_1() { cout << "using mid_1::~Mid_1" << endl; }

    void f() { cout << "using mid_1::f" << endl; }
};
class Mid_2 :public Base
{
private:
    int a;
public:
    void f() { cout << "using mid_2::f" << endl; }

    Mid_2(int _a = 2, int b = 1) :
        Base(b), a(_a)
    {
        cout << "using Mid_2::Mid_2" << endl;
    }

    ~Mid_2() { cout << "using mid_2::~Mid_2" << endl; }
};
class D :public Mid_1, public Mid_2
{
private:
    int x;
public:
    D(int _x, int m_1, int m_2) :
        Mid_1(m_1),
        Mid_2(m_2),
        x(_x) {
        cout << "using D::D" << endl;
    }

    ~D() { cout << "using D::~D" << endl; }

    void func()
    {
        Mid_1::f();

    }
};
int main()
{
    D d(1, 2, 3);
    //    d.func();

    return 0;
}

菱形继承
d对象里面先调用Mid_1,创建一个Base对象a,接着创建Mid_1,()
然后调用Mid_2,创建Base对象b,接着创建Mid_2,
最后,创建D对象,D对象含有2个Base的对象,并且先创建a后创建b
所以析构的时候先析构b后析构a,析构顺序从派生类到基类析构

(Ⅱ)虚拟多继承

#include <iostream>

using namespace std;
class Top {
public:
    Top() { cout << "using Top::Top\n"; }
};
class Base : public Top
{
private:
    int a;
public:
    Base(int c = 0) { a = c; cout << "using Base::Base" << endl; }
    virtual void f() { cout << "using Base::f" << endl; }
    virtual ~Base() { cout << "using Base destructor." << endl; }
};
class Mid_1 :virtual public Base
{
private:
    int a;
public:
    Mid_1(int _a = 1, int b = 0) :
        Base(b), a(_a)
    {
        cout << "using Mid_1::Mid_1" << endl;
    }

    ~Mid_1() { cout << "using mid_1::~Mid_1" << endl; }

    void f() { cout << "using mid_1::f" << endl; }
};
class Mid_2 :virtual public Base
{
private:
    int a;
public:
    void f() { cout << "using mid_2::f" << endl; }

    Mid_2(int _a = 2, int b = 1) :
        Base(b), a(_a)
    {
        cout << "using Mid_2::Mid_2" << endl;
    }

    ~Mid_2() { cout << "using mid_2::~Mid_2" << endl; }
};
class D :virtual public Mid_1, virtual public Mid_2
{
private:
    int x;
public:
    D(int _x, int m_1, int m_2) :
        Mid_1(m_1),
        Mid_2(m_2),
        x(_x) {
        cout << "using D::D" << endl;
    }
    void f(){
    
    }
    ~D() { cout << "using D::~D" << endl; }

    void func()
    {
        Mid_1::f();
        Mid_2::f();
    }
};
int main()
{
    D d(1, 2, 3);
    //    d.func();

    return 0;
}

D沿着2条路径继承了Base总共2次,所以虚拟继承时,D对象里面只保留了1个Base类的 对象,创建Mid_1和Mid_2的对象前先把他们的共同基类对象创建,接着按照继承顺序来创建对象,所以先创建了Base,Mid_1,Mid_2最后创建D,先析构D,后析构Mid_2,Mid_1,再析构Base

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿维的博客日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值