C++ 类的默认函数

用户自定义一个类,简单的可以看成是一个新的类型,与C++标准里面的数据类型使用差不多。但在面向对象编程中,我们知道任何一个对象必须要通过构造函数才能创建,以及可以将一个对象拷贝给另一个对象,将一个对象作为参数传递给一个函数等。

C++默认函数
  • 一个没有任何成员函数的类,其至少有如下四个默认函数
    • 默认构造函数
    • 默认拷贝构造函数
    • 默认“=”运算符重载函数
    • 析构函数

既然是默认函数,那也就是说即便类里面一个成员函数没有,这几个函数仍然存在(想来也是必然,就算啥成员函数都没有,但总需要创建对象,赋值,作为参数传递等),先看下几个默认函数长什么样,这里只是为了更加形象的表示,实际类中是看不到这几个函数的,**一旦类里面有与这几个函数同名的函数,那相
应的默认函数都被覆盖了**

class Base{
private:
    int a;
    int b;
public:
    Base(){};               //默认构造函数
    Base(const Base & cb)    //默认拷贝构造函数
    {
        //利用对象b对类对象成员属性进行简单的拷贝
        this->a = cb.a;
        this->b = cb.b;
    }
    Base & operator=(const Base & cb)  //默认“=”运算符重载函数
    {
        //利用对象b对类对象成员属性进行简单的拷贝
        this->a = cb.a;
        this->b = cb.b;        
    }
    ~Base(){}               //析构函数
};

默认构造函数用于创建对象,主要有以下两种方式
class Base{
public:
    int a;
    int b
};

Base cb;
Base * pcb = new Base();

以上两种创建对象的方式,均会调用默认构造函数调用创建对象。由于这里类B没有任何构造函数,因此直接调用默认构造函数,需要注意,默认构造函数只是为对象申明空间,而并不会将对象成员进行初始化,如下:

class Base{
public:
    int a;
    int b
};

Base cb;
Base * pcb = new Base();

cout << cb.a << endl;

// cb.a输出为一个随机值
默认拷贝构造函数,主要用在初始化、传值
  • 用一个对象初始化另一个对象
  • 将一个对象作为函数参数以值传递的方式传递(与引用方式区分)
  • 将一个对象作为函数返回值
class Base{
};

void fun(Base ba);
Base fun1();

Base cb;

Base cb1(cb);    //调用默认拷贝构造函数
Base cb2 = cb;   //调用默认拷贝构造函数
Base cb3;

fun(cb);         //调用默认拷贝构造函数
cb3 = fun1();    //调用默认拷贝构造函数

注意Base cb2 = cb; 这里是初始化,并不是赋值!

默认“=”运算符重载函数, 主要用在赋值语句
  • 赋值语句与初始化的区别:初始化是在申明对象的时候,同时对其“赋值”,是在分配内存的同时完成内存内容填充;赋值是先分配内存,再从其它对象将内容拷贝到该内存空间。

class Base{
};

void fun(Base ba);


Base cb;
Base cb2;        //调用默认构造函数

cb2 = cb;        //调用默认“=”操作符重载函数
默认析构函数:在对象销毁(可以是系统自动销毁或者用户主动销毁)时调用。

class Base{
};

int main()
{

    Base cb;         //当前作用域之后销毁cb对象,此处是main函数结束即销毁对象
    Base * pcb = new Base();   

    delete pcb;      //调用delete pcb手动销毁pcb指向的对象
    return 0;
}

需要注意默认拷贝构造函数默认“=”操作符重载函数都会检查对象是否初始化,前面提到过,默认构造函数在创建对象的时候,如果有成员变量,则不会对成员变量进行初始化,因此在利用该对象初始化其它对象或者赋值给其它对象,则会编译出错。

class Base{
public:
    int a;
};

int main()
{
    Base cb;      
    Base cb1(cb);       //编译错误提示:使用了未初始化的局部变量
    Base cb2 = cb;      //编译错误提示:使用了未初始化的局部变量
    return 0;
}

使用忠告:
  • 为自己的每个类重新编写构造函数,至少要有一个没有参数的构造函数(也即替代默认构造函数)。
  • 构造函数里面对类成员进行初始化,尽量使用初始化列表的方式
  • 如果有用对象进行初始化或者赋值、拷贝、传值,不要依赖类默认的拷贝构造与“=”运算符重载函数。牵涉到深拷贝与浅拷贝,尽量自己实现这两个函数,详细指定如何拷贝。
C++ 默认生成的成员函数主要包括以下六种,这些函数在特定条件下由编译器自动生成: ### 默认构造函数 默认构造函数用于初始化对象,当用户未显式定义任何构造函数时,编译器会生成一个无参的默认构造函数。对于内置型(如 `int`、`long` 等),默认构造函数不会进行初始化;而对于自定义型,则会调用其默认构造函数进行初始化 [^2]。 ### 析构函数 析构函数用于在对象生命周期结束时释放资源,例如动态分配的内存或打开的文件等。若用户未显式定义析构函数,系统会在需要时自动生成一个默认析构函数默认析构函数不会对内置型做任何操作,但对于自定义型,会调用其析构函数 [^1]。 ### 拷贝构造函数 拷贝构造函数用于使用一个已存在的对象来初始化新对象。如果用户未显式定义拷贝构造函数,编译器将自动生成一个按成员浅拷贝的版本。该函数接受一个当前型的常量引用作为参数 [^3]。 ### 拷贝赋值运算符 拷贝赋值运算符用于将一个对象的值赋给另一个已存在的对象。当用户未显式定义拷贝赋值运算符时,编译器会自动生成一个按成员进行浅拷贝的版本。该运算符通常返回当前对象的引用,并接受一个当前型的常量引用作为参数 [^3]。 ### 移动构造函数 移动构造函数用于使用一个临时对象(右值)来初始化新对象。在 C++11 及以后的标准中,如果用户未显式定义移动构造函数,且没有显式定义某些其他特殊成员函数(如拷贝构造函数、拷贝赋值运算符等),则编译器可能会生成一个默认的移动构造函数 [^3]。 ### 移动赋值运算符 移动赋值运算符用于将临时对象(右值)的值赋给一个已存在的对象。与移动构造函数似,在 C++11 及以后的标准中,如果用户未显式定义移动赋值运算符,且满足一定条件,编译器会自动生成一个默认的版本 [^3]。 ### 特殊行为说明 - **构造函数和析构函数**:不能被重载,一个只能有一个析构函数和一个默认构造函数 [^1]。 - **自动调用**默认构造函数在对象实例化时自动调用,而析构函数在对象生命周期结束时由编译器自动调用 [^4]。 - **资源管理**:析构函数主要用于清理对象占用的资源,例如关闭文件句柄或释放内存 [^4]。 以下是示例代码,展示了一个简单默认生成的成员函数的行为: ```cpp class MyClass { public: // 默认构造函数 MyClass() {} // 析构函数 ~MyClass() {} // 拷贝构造函数 MyClass(const MyClass& other) {} // 拷贝赋值运算符 MyClass& operator=(const MyClass& other) { if (this != &other) { // 实现拷贝逻辑 } return *this; } // 移动构造函数 MyClass(MyClass&& other) noexcept {} // 移动赋值运算符 MyClass& operator=(MyClass&& other) noexcept { if (this != &other) { // 实现移动逻辑 } return *this; } }; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值