类的六大默认构造函数

本文详细介绍了C++中的构造函数与析构函数的作用及使用场景,包括构造函数的不同形式及其初始化方式,并深入探讨了拷贝构造函数与赋值操作符的功能与实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

缺省的构造函数和析构函数,等于放弃了自己初始化和清除的机会;缺省的拷贝构造和缺省的赋值函数,采用“位拷贝和值拷贝”。若类中出现指针时,这两个函数出错。

class String
{
public:
String(const char *str = NULL);//构造
~String();//析构
String (const String &s);//拷贝构造
String& operator=(const String &s);//赋值
String* operator&();//普通引用方法
String* operator&()const;//常引用方法
private:
char* m_str;
};

构造函数与析构函数

构造函数和析构函数表明了一个对象的由生到死的过程。一个对象只能调用一次构造方法,一个类有且只有一个析构方法。

构造函数作用:
1、实例化对象 2、对对象成员进行初始化 3、强制类型转化(通过中间桥梁实现)

#

类的数据成员的初始化方式(二者效率不同)
1、初始化列表方式
2、函数体内赋值
3、类的const 常量只能在初始化列表内初始化,不能在函数体内进行赋值。

#

构造顺序
1、遇到对象自动调用其构造方法,如若有继承关系时,则先调用父类的构造方法;当主函数中构造对象完成时自动调用析构函数。
2、先构造者后析构,因为构造函数中,对象是通过堆栈的方式进行存储的,同理 析构时按照出栈的顺序。

成员对象初始化的次序完全不受他们在初始化列表中的次序,只与成员对象在类中的声明次序有关。

#include<iostream>
using namespace std;

class Test
{
public:
    Test()
    {
    cout<<this<<endl;//6c
    }
    Test(int d,int num):number(num),data(d)
    {
        cout<<this<<endl;//64
        cout<<"data-->"<<this->data<<endl;
        cout<<"number-->"<<this->number<<endl;
    }
    ~Test()
    {
        cout<<"~Test()"<<this<<endl;
    }
private:
    int data;
    int number;
};

void main()
{
    Test t;
    Test t2(1,2);
}

这里写图片描述

强制类型转化

#include<iostream>
using namespace std;
class Test
{
public:
    Test()
    {
        cout<<"Test()"<<this<<endl;
    }
    Test(int d):data(d)
    {
        cout<<"Test()"<<this->data<<endl;
    }
    /*int GetData()const
    {
        return data;
    }
    */
    operator int()
    {
        return data;
    }

    ~Test()
    {
        cout<<"Free Test()"<<this<<endl;
    }
private:
    int data;
};
void main()
{
    //Test t1(); 声明函数,能编译、能运行,但是是错误的
    Test t(1);
     t =100;//100通过构建函数构造中间零时对象,对象给对象赋值
     //若构造函数前面加上explicit关键字时,则赋值时必须显示调用即  t =(Test) 100;    
     int value;
    //通过公有方法获取data值
    //value = t.GetData();
    //调用operator int()方法,将对象类型强制转换为值类型
    value = t;

}

这里写图片描述

构造函数,有两种方式:

1、定义无参构造函数 2、定义所用带默认值的构造函数 且 二者方式只能用一种。一个类只能有一个带默认值的构造函数。不然程序产生二义性。当带默认值的参数,没有初始化时,则产生随机值。

#include<iostream>
using namespace std;

class Test
{
public:
    //无参构造
    Test()
    {}
    Test(int d):data(d)
    {
        cout<<data<<endl;
    }
    //带默认值的构造
    /*
    Test(int d=0)
    {
        data = d;
        cout<<data<<endl;
    }
    */
private:
    int data;
};
void main()
{
    Test t(2);
}

拷贝构造与赋值函数

拷贝构造函数:用一个已有对象去初始化一个新的对象。

产生拷贝构造的条件:

1、用已有对象去初始化新的对象
2、函数参数类型传递
3、函数返回值类型的对象。

include<iostream>
using namespace std;
include<vld.h>
class Test
{
public:
    Test()
    {}
    Test(int d):data(d)
    {}
    void print()
    {
        cout<<data<<endl;
    }
    //不用引用,自己解释自己会产生循环递归
    Test(const Test &other)
    {
        data = other.data;
    }
    ~Test()
    {
        cout<<"~Test()"<<endl;
    }
private:
    int data;
};
void fun(Test s1)
{
    cout<<"fun()"<<endl;
}
Test fn()
{
    Test s2(1);
    //返回s2之前会产生无名的临时对象,即用s2去构造对象 因此调用拷贝构造函数
    return s2;
}
void main()
{
    Test t(2);
    //两者一样
    //Test t1(t);
    Test t1= t;
    t.print();
    t1.print();
    //对象作为函数参数
    fun(t1);
    //对象作为函数的返回值
    t=fn();
}

这里写图片描述

return 返回时,实际调用了拷贝构造函数构造了一个无名的临时对象

int  Sum(int a,int b)
{
    return sum=a+b;
    //返回的不是sum,sum在离开作用域时,已经被释放;会产生一个临时无名对象,并将sum 值传给该对象。
}
void main()
{
    int val=Sum(1,2);
}

赋值

赋值相当于a对象的成员参数,给b的成员参数赋值。
1、是否把返回值的类型声明为该类型的引用。
2、是否把传入的参数声明为常量引用。
3、是否释放自己已有空间。
4、是否判断传入的参数和当前的实例(*this)是不是一个实例。

#

#include<iostream>
using namespace std;
#include<vld.h>
class Test
{
public:
    Test(int d=0):data(d)
    {}
    void print()
    {
        cout<<data<<endl;
    }
    Test(const Test &other)
    {
        data = other.data;
    }
    /*
    1.const:表明对象的数据成员在赋值过程中,不被修改
    2.&s:减少调用一次拷贝构造函数,也提高效率,在程序中,当对象不受函数作用域的影响时,可以使用&
    3.Test 为了是连续对象间赋值t1=t2=t3;
    4.在返回类的对象*this时,会产生临时对象调用拷贝构造函数。&为了不构造临时对象,减少调用拷贝构造
    t1.operator=(t2.operator=(t3))
    */
    Test& operator=( const Test &s)
    {
        if(this != &s)
        {
            data = s.data;
        }
        //返回当前对象
        return *this;
    }
    ~Test()
    {
        cout<<"~Test()"<<endl;
    }
private:
    int data;
};

void main()
{
    Test t(10);
    Test t1(t);
    Test t2;
    t2 = t1;
    //t2.operator=(t1)
    //t2.operator=(&t2,t1)
    //下面的const用来说明当前对象不允许修改
    //Test& operator(Test *const this,const  Test &s )
}

普通引用方法与常引用方法

#include<iostream>
using namespace std;
#include<vld.h>

class String
{
public:
    String(char *str=NULL)
    {
    //构造的对象为NULL时,String a(""|NULL|0)和String a()不一样
        if(str == NULL)
        {
            m_str = new char[1];
            *m_str = '\0';
        }
        else
        {   
            m_str = new char[strlen(str)+1];
            strcpy(m_str,str);
        }
    }
    //深拷贝
    String(const String &s)
    {
         m_str = new char[strlen(s.m_str)+1];
        strcpy(m_str,s.m_str);
    }
    //深赋值
    String& operator=(const String &other)
    {
        if(this != &other)
        {
        String tmp=other;
        char *pstr=m_str;
        m_str= tmp.m_str;
        tmp.m_str = pstr;
        }
        return *this;

    }
    //普通引用方法
    String* operator&()
    {
        return this;
    }
    //常方法
    const String* operator&()const
    {
        return this;
    }
    ~String()
    {
        delete []m_str;
        m_str = NULL;
    }
private:
    char *m_str;
};
void main()
{
    String s("123");
    String s1=s;
    String s2;
    s2=s1;
    String *p =&s1;
    const String s3("Hello");
    const String *q =&s3;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值