C++构造析构

C++构造析构

目录

1.单个类说明

类的生命周期起始于构造函数,终止于析构函数.可以在栈(直接使用)上创建也可以在堆(new 产生)上创建,也可以限制允许在一种情况下创建. 其中构造函数可以重载(不同的参数匹配不同的构造,达到多态目的),析构不能重载(析构本身无参). 当创建一个类时c++会创建以下默认函数

  • default构造函数 (无参构造函数)
  • 拷贝构造函数 (由相同的类创建本类)
  • =重载操作符函数 (本类已经存在,用于对本类进行重新赋值,默认生成左值复制和右值复制) 右值复制 c++11才有)
  • 析构函数 (生命周期结束时调用)
  • 移动构造函数 (c++11才有)

类的动态创建可以分为2步:第一步分配内存,第二步调用构造函数. 因此有二种不同的玩法:

  • 玩法一(普通玩法):分配内存和调用构造一起 如:
class A{int m;};

A *pa = new A(); //堆上构造

delete pa;     //释放析构
  • 玩法二(高级玩法):先分配内存 然后再调用构造函数 如:
class A{int m;};

A *pa = (A *)malloc(sizeof(A) *2); //先分配内存(可以分配很多)

new(&pa[0]) A(); //只调用构造(如果有内存已经分配好,可以重复利用  STD库 vector就是该原理)
new(&pa[1]) A();

pa[0].~A();  //只调用析构
pa[1].~A();

free(pa);      //释放内存

2.多个类说明

类可以继承其它类(其它类称为父类或者超类). 也可以将其它类用于本类的成员(其它类称为成员类).

类的构造顺序

如果有父类递归构造,从最远的父类开始构造. 构造本类时,按成员在本类的顺序(static 成员除外)依次构造成员.(如果构造函数里顺序不一致会警告,必须在构造函数中保持一致)

析构顺序

如果有父类先析构自己然后析构父类,依次析构(和构造相反). 析构本类时,按成员在本类的反顺序依次析构(和构造相反).

注意:析构时不要调用虚函数!

3.例程


#include <signal.h>
#include "wutility/WUtils.h"

/**构造函数   类第一次实例化时调用     (new一个对象  或者 其它实例对象)                  可以有多种构造函数,由输入参数匹配对应的构造函数
 * 析构函数   实例消亡时调用                (delete 或者局部变量出了作用域  或者程序结束)     只能由一个析构函数
 */

/**
 * new 调用 构造函数
 * delete 调用析构函数
 *  malloc 和free 什么都不调用
 */

class Point //类名
{
public: //公共的 (外部都能调用)
    ~Point() //析构函数
    {
        WDBG("~Point");
    }

    Point() : m_x(0), m_y(0) //默认构造函数
    {
        WDBG("默认构造 Point");
    }

    Point(s32 xIn, s32 yIn) : m_x(xIn), m_y(yIn) //有参构造函数 (尽量让输入参数和类的成员名字不同)
    {
        WDBG("有参数构造 Point");
//        x = xIn; 可以再下面复制. 效率没有放:后面高(特别是类)
//        y = yIn;
    }

    s32 x() //get方法 不需要写get (默认本类不能出现x变量!!)
    {
        return m_x;
    }

    s32 y()
    {
        return m_y;
    }

    void setX(s32 x) //set 方法必须写set
    {
        m_x = x; // m_x 私有的成员只能通过函数调用
        WDBG("Point setX");
    }

    void setY(s32 y)
    {
        m_x = y;
        WDBG("Point setY");
    }

    std::string toString() const//格式字符串 类的默认调用方法
    {
        return WString::formats("[%, %]", m_x, m_y);
    }

private: //私有的 (只有本类能调用)
    s32 m_x; //类的成员必须以m_ 开头
    s32 m_y;
};


class Point2 //和 Point类一样给下面测试用
{
public:
    ~Point2() //析构函数
    {
        WDBG("~Point2");
    }

    Point2() : m_x(0), m_y(0) //默认构造函数(如果没有写该函数,必须传入指定参数才能构造)
    {
        WDBG("默认构造 Point2");
    }

    Point2(s32 xIn, s32 yIn) : m_x(xIn), m_y(yIn) //有参构造函数
    {
        WDBG("有参数构造 Point2");
//        x = xIn;
//        y =yIn;
    }

    s32 x()
    {
        return m_x;
    }

    s32 y()
    {
        return m_y;
    }

    void setX(s32 x)
    {
        m_x = x;
    }

    void setY(s32 y)
    {
        m_x = y;
    }

    std::string toString() const
    {
        return WString::formats("[%, %]", m_x, m_y);
    }

private:
    s32 m_x;
    s32 m_y;
};


//使用 Point 类的成员
class PointTh
{
public:
    ~PointTh() //析构函数
    {
        WDBG("~PointTh");
    }

    PointTh() : m_th(0) //默认构造函数
    {
        WDBG("默认构造 PointTh");
    }

    //注意构成函数中如果成员函数为有参构造函数需放于  :后面依次构造. 构造顺序为 成员的顺序
    //如果类的成员需要使用默认构造函数可以不写
    PointTh(s32 xIn, s32 yIn, float thIn) : m_p(xIn, yIn), m_th(thIn)//有参构造函数
    {
        WDBG("有参数构造 PointTh");
//        x = xIn;
//        y =yIn;
    }

    void setTh(s32 th)
    {
        m_th = th;
    }

    s32 x()
    {
        return m_p.x(); //使用成员方法调用  .为方法
    }

    s32 y()
    {
        return m_p.y();
    }

    s32 th()
    {
        return m_th;
    }

    std::string toString() //std:: 为命令空间
    {
        return WString::formats("[%, %,th:%]", m_p.x(), m_p.y(), m_th); //WString :: 为类的静态函数
    }

private:
    Point m_p;   // 有类的成员(可以调用 Point类的public方法)
    float m_th;  //弧度
};


//继承Point类
// Point的public 方法为本类的方法(如果本类有相同名字则,父类不起作用)
class PointThChild : public Point
{
public:
    ~PointThChild() //析构函数
    {
        WDBG("~PointThChild");
    }


    PointThChild() : Point() //默认构造函数(空的默认构造函数可以不写)
    {
        WDBG("默认构造 PointThChild");
    }

#if 0
    PointThChild() //可以不写
    {
    }
#endif

    //注意构成函数中如果父类为有参构造函数,需放:后的第一个位置
    //构造顺序  父类先构造,然后为本类的成员!!
    //析构的顺序 相反
    PointThChild(s32 xIn, s32 yIn, float thIn) : Point(xIn, yIn), m_th(thIn)//有参构造函数
    {
        WDBG("有参数构造 PointThChild");
    }

    void setTh(s32 th)
    {
        m_th = th;
    }

    void setX(s32 x) //父类的setX不在起作用
    {
        WDBG("PointThChild setX");
        Point::setX(x); //可以显示调用父类的方法
    }

    std::string toString()
    {
        return WString::formats("[%, %,th:%]", x(), y(), m_th);
    }

private:
    float m_th; //弧度
};


//表示 构造和析构的顺序
class Rect
{
public:
    Rect(s32 x1, s32 y1, s32 x2, s32 y2) : m_p1(x1, y1), m_p2(x2, y2)
    {
    }

    std::string toString()
    {
        return WString::formats("[%, %, %, %]", m_p1.x(), m_p1.y(), m_p2.x(), m_p2.y());
    }

private:
    Point   m_p1;
    Point2  m_p2;
};

//new的使用
//(只有类中有自己new对象时.需要delete成员. 或者外部移交给本类的new对象)
class RectNew
{
public:
    ~RectNew()
    {
        WDBG("~RectNew");

        if(m_p1 != WNULL) //由于为new产生必须析构. 防止内存泄露
        {
            delete m_p1;
            m_p1 = WNULL;
            WDBG("~RectNew 释放内存");
        }
    }

    RectNew() : m_p1(WNULL)
    { //默认构造函数 指针类型 强制为NULL
        WDBG("RectNew 默认构造函数");
    }

    RectNew(s32 x, s32 y)
    {
        m_p1 = new Point(x, y);
        //有参数的 new 对象 后面为 构造函数填入对应的参数

        WDBG("RectNew 有参数构造函数");
    }

    std::string toString()
    {
        if(m_p1 == WNULL)
        {
            return WString::formats("[NULL, NULL]");
        }

        return WString::formats("[%, %]", m_p1->x(), m_p1->y());
    }

private:
    Point   *m_p1;
};

//不同构造函数出现的场景
class Str
{
public:
//    ~Str() //默认析构函数 不写,则自动生成
//    {
//    }
//
    Str()
    {
    }

    Str(const Str& in) : m_st(in.m_st)
    {
        WDBG("Str 复制构造左值");
    }

    Str(Str&& in) : m_st(std::move(in.m_st))
    {
        WDBG("Str 复制构造右值");
    }

    Str& operator=(const Str &p)
    {
        WDBG("赋值 左值");
        m_st = p.m_st;

        return *this;
    }

    Str& operator=(Str &&p)
    {
        WDBG("赋值 右值");
        m_st = std::move(p.m_st);
        return *this;
    }

    std::string m_st;
};

/*******
c++中创建一个类默认生成的函数
 •default构造函数(无参构造函数)
 •拷贝构造函数
 •=重载操作符函数
 •析构函数
 •移动构造函数
 */


//默认构造的生成
class Ct
{
public:

    s32         m_val;
    s32         m_valB;
    std::string m_st;
    Str         m_out;


    std::string toString() const
    {
        return WString::formats("m_val[%],m_valB[%],m_st[%],m_out[%]",
                                m_val, m_valB, m_st, m_out.m_st);
    }
};



//结构体和 class 等同
//区别:结构体 默认为 public  class 默认为private
struct St
{   //默认都是public
    s32         m_val;
    s32         m_valB;
    std::string m_st;
    Str         m_out;


    std::string toString() const
    {
        return WString::formats("m_val[%],m_valB[%],m_st[%],m_out[%]",
                                m_val, m_valB, m_st, m_out.m_st);
    }
};

//extern void tsb();

static void test()
{
//    tsb();
    {
        Point p1;

        WDBG("p1=%", p1);

        //调用无参数的构造函数
    }

    WDBG("\r\n");

    {
        Point p2(3, 4);

        WDBG("p2=%", p2);

        //调用有参数的构造函数
    }

    WDBG("\r\n");

    {
        PointTh p3(4, 5, 2.0);

        WDBG("p3=%", p3);

        //成员函数 m_p 先构成后为 m_th
        //如果成员函数为基本类型 不调用构造函数!!
    }

    WDBG("\r\n");

    {
        PointTh p4(4, 5, 2.0);

        WDBG("p4=%", p4);
    }

    WDBG("\r\n");

    {
        Point p5;
        PointTh p6(3, 4, 3.0);

        WDBG("p5=%, p6=%", p5, p6);

        //构造顺序 为 p5 --> p6
        //析构顺序为 p6--> p5
    }


    WDBG("\r\n");

    {
        Rect r(1, 2, 3, 4);

        WDBG("rect=%", r);


//        Rect b; //没写默认构造函数编译失败

        //析构顺序为 m_p2--> m_p1
    }

    {
        WDBG("\r\n");
        PointThChild p(1, 2, 3);

        WDBG("PointThChild p=%", p);

        p.setY(10); //调用父类的方法

        p.setX(10); //调用子类的方法
        WDBG("PointThChild p=%", p);
    }

    WDBG("\r\n");

    {
        RectNew rn1;

        WDBG("rn1=%", rn1);
    }

    WDBG("\r\n");

    {
        RectNew rn2(2, 3);


        WDBG("rn1=%", rn2);
    }


    WDBG("\r\n");
    WDBG("\r\n");
    WDBG("\r\n");

    { //默认生成的函数和 左值右值
        Ct a;

        a.m_val = 1;
        a.m_valB = 2;
        a.m_st = "123";
        a.m_out.m_st = "out";

        WDBG("Ct a=%", a);

        Ct b(a); //默认生成的复制构造函数  左值

        WDBG("\r\n");
        WDBG("Ct a=%", b);


        Ct c;

        c = b;  //默认生成的赋值函数 左值
        WDBG("\r\n");
        WDBG("Ct c=%", c);

        {
            WDBG("\r\n");

            Ct d(std::move(c));  //默认生成的复制构造函数 右值
            WDBG("Ct d(std::move(c)=%", d);

            Ct h;
            WDBG("\r\n");

            h = std::move(d);  //默认生成的赋值函数 右值
            WDBG(" Ct h = std::move(d)=%", h);
        }
    }

    WDBG("\r\n");
    WDBG("\r\n");
    WDBG("\r\n");

    { //默认生成的函数和 左值右值
        St a;

        a.m_val = 1;
        a.m_valB = 2;
        a.m_st = "123";
        a.m_out.m_st = "out";

        WDBG("St a=%", a);

        St b(a); //默认生成的复制构造函数  左值

        WDBG("\r\n");
        WDBG("St a=%", b);


        St c;

        c = b;  //默认生成的赋值函数 左值
        WDBG("\r\n");
        WDBG("St c=%", c);

        {
            WDBG("\r\n");

            St d(std::move(c));  //默认生成的复制构造函数 右值
            WDBG("St d(std::move(c)=%", d);

            St h;
            WDBG("\r\n");

            h = std::move(d);  //默认生成的赋值函数 右值
            WDBG("St h = std::move(d)=%", h);
        }
    }



    WDBG("\r\n");

}



/**


[DBG] [2021-07-15 15:20:20.813] [main.cpp::main:668] 课程开始
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Point:18] 默认构造 Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:371] p1=[0, 0]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~Point:13] ~Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:376]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Point:23] 有参数构造 Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:381] p2=[3, 4]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~Point:13] ~Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:386]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Point:23] 有参数构造 Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::PointTh:129] 有参数构造 PointTh
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:391] p3=[4, 5,th:2.000]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~PointTh:118] ~PointTh
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~Point:13] ~Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:397]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Point:23] 有参数构造 Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::PointTh:129] 有参数构造 PointTh
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:402] p4=[4, 5,th:2.000]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~PointTh:118] ~PointTh
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~Point:13] ~Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:405]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Point:18] 默认构造 Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Point:23] 有参数构造 Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::PointTh:129] 有参数构造 PointTh
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:411] p5=[0, 0], p6=[3, 4,th:3.000]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~PointTh:118] ~PointTh
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~Point:13] ~Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~Point:13] ~Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:418]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Point:23] 有参数构造 Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Point2:76] 有参数构造 Point2
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:423] rect=[1, 2, 3, 4]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~Point2:66] ~Point2
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~Point:13] ~Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:432]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Point:23] 有参数构造 Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::PointThChild:192] 有参数构造 PointThChild
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:435] PointThChild p=[1, 2,th:3.000]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::setY:47] Point setY
[DBG] [2021-07-15 15:20:20.815] [main.cpp::setX:202] PointThChild setX
[DBG] [2021-07-15 15:20:20.815] [main.cpp::setX:41] Point setX
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:440] PointThChild p=[10, 2,th:3.000]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~PointThChild:172] ~PointThChild
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~Point:13] ~Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:443]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::RectNew:253] RectNew 默认构造函数
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:448] rn1=[NULL, NULL]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~RectNew:241] ~RectNew
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:451]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Point:23] 有参数构造 Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::RectNew:261] RectNew 有参数构造函数
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:457] rn1=[2, 3]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~RectNew:241] ~RectNew
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~Point:13] ~Point
[DBG] [2021-07-15 15:20:20.815] [main.cpp::~RectNew:247] ~RectNew 释放内存
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:461]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:462]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:463]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:473] Ct a=m_val[1],m_valB[2],m_st[123],m_out[out]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Str:292] Str 复制构造左值
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:477]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:478] Ct a=m_val[1],m_valB[2],m_st[123],m_out[out]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::operator=:302] 赋值 左值
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:484]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:485] Ct c=m_val[1],m_valB[2],m_st[123],m_out[out]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:488]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Str:297] Str 复制构造右值
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:491] Ct d(std::move(c)=m_val[1],m_valB[2],m_st[123],m_out[out]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:494]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::operator=:310] 赋值 右值
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:497]  Ct h = std::move(d)=m_val[1],m_valB[2],m_st[123],m_out[out]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:501]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:502]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:503]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:513] St a=m_val[1],m_valB[2],m_st[123],m_out[out]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Str:292] Str 复制构造左值
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:517]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:518] St a=m_val[1],m_valB[2],m_st[123],m_out[out]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::operator=:302] 赋值 左值
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:524]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:525] St c=m_val[1],m_valB[2],m_st[123],m_out[out]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:528]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::Str:297] Str 复制构造右值
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:531] St d(std::move(c)=m_val[1],m_valB[2],m_st[123],m_out[out]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:534]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::operator=:310] 赋值 右值
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:537] St h = std::move(d)=m_val[1],m_valB[2],m_st[123],m_out[out]
[DBG] [2021-07-15 15:20:20.815] [main.cpp::test:543]
*/


/** 信号退出回调
 * @param in signum 信号数
 * @return 无
 **/
static void closeHandler(int signum)
{
    WARG_NO_USE(signum);
    int save_errno = errno;

    setSysExit();
    errno = save_errno;
}


int main(int argc, char **argv)
{
    signal(SIGPIPE, SIG_IGN); //忽略网络异常
    signal(SIGINT, closeHandler); 
    signal(SIGTERM, closeHandler); 

    WDBG("课程开始");


    test();
}