杂货边角(16):C++11之后,类的所有构造函数

本文深入探讨C++中默认构造函数的概念,包括构造函数、拷贝构造函数、拷贝赋值函数等,并通过具体代码示例展示了这些函数的工作原理及其在不同场景下的应用。

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

C++类声明中,编译器会默认帮助程序员生成一些他们未定义的成员函数,这样的函数被称为“默认函数”,这包括了以下一些自定义类型的成员函数:
1.构造函数;
2.拷贝构造函数
3.拷贝赋值函数(operator= (const Class & T) )
4.移动构造函数
5.移动拷贝赋值函数(operator= (Class&& T) )
6.析构函数
但是程序员一旦在类的定义中显式地声明上述构造函数的任何一种,则编译器将不会在为该类定义该种类下的默认版本。最常见的便是一旦声明了带参构造函数,则同时也需要程序员自己提供无参构造函数,否则该类将不存在无参构造函数。(但不是说定义了构造函数,系统不提供拷贝构造函数、移动构造函数等,即上述1、2、 3等之间彼此不冲突)。

#include <string>
#include <iostream>
#include <memory>
#include <vector>
#include <string.h>

using namespace std;

class CMyString {
private:
    char * buf;
    int len;

private:
    void copy(const char* s) {
        buf = new char[len+1];
        memcpy(buf, s, len);
        buf[len] = '\0';
    }

public:
    CMyString() {
        std::cout << "non-param constructor" << std::endl;

        buf = nullptr;
        len = 0;
    }

    CMyString(const char* str = nullptr) {
        if (str == nullptr) {
            std::cout << "one-param constructor" << std::endl;

            buf = nullptr;
            len = 0;
        }
        else {
            std::cout << "one-param constructor: " << str << std::endl;
            len = strlen(str);
            copy(str);
        }
    }

    CMyString(const CMyString& str) {                               //拷贝构造函数
        std::cout << "copy constructor: " << str.buf << std::endl;

        len = str.len;
        copy(str.buf);
    }

    CMyString(CMyString&& str) {
        std::cout << "move constructor: " << str.buf << std::endl;  //移动构造函数

        //也可以直接使用std::move

        len = str.len;
        buf = str.buf;



        str.len = 0;
        str.buf = nullptr;
    }

    CMyString& operator=(const CMyString& str) {
        std::cout << "copy and assignment func: " << str.buf << std::endl;   //拷贝赋值函数

        if (&str != this) {
            if (buf != nullptr) {
                delete[] buf;
                buf = nullptr;
            }

            len = str.len;
            copy(str.buf);
        }

        return *this;
    }



    CMyString& operator=(CMyString&& str) {
        std::cout << "move and assignment func: " << str.buf << std::endl; //移动赋值函数

        if (this != &str) {

            if (buf != nullptr) {
                delete[] buf;
                buf = nullptr;
            }

            len = str.len;
            buf = str.buf;
            str.len = 0;
            str.buf = nullptr;
        }

        return *this;
    }

    ~CMyString() {
        if (buf == nullptr)
        {
            std::cout << "destructor" << std::endl;
        }
        else
        {
            std::cout << "destructor: " << buf << std::endl;
            delete[] buf;
            buf = nullptr;
        }
    }

    void print() {
        if (buf != nullptr)
            std::cout << buf << std::endl;
        else
            std::cout << "buf is null" << std::endl;
    }


};

void func1(CMyString str) {

}

CMyString func2() {
    CMyString s("34");
    std::cout << "Resource from " << __func__ << ": " << hex << &s << endl;
    return s;
}

void func3(CMyString && str) {
    CMyString tmp = std::move(str);  //move constructor
    //CMyString tmp = str;   //copy constructor这是因为虽然str初始声明为右值引用,但一旦
    //占据表达式右值的位置时,则该右值引用的语义将变成不折不扣的左值,除非用move强制声明
}

void test0() {
    CMyString s1("12");

    func1(s1); //对象str尚未初始化,会调用拷贝构造函数

    CMyString s2(func2()); // 对象s2尚未初始化,会产生临时对象,调用移动构造函数
    std::cout << "Resource from " << __func__ << ": " << std::hex << &s2 << endl;
    //这一步存在一步编译器优化,比移动语义更加激进的优化方式,直接将func2()返回的temp对象
    //的指针,直接赋给s2,故这一步实际并没有调用任何构造函数RVO return value optimization
    //CMyString s2(std::move(func2())); //这样写则会体现出移动语义的鸠占鹊巢,存在临时对象的构造和析构

    CMyString s3 = "56";//对象s3尚未初始化,虽然是有'=6',但是其实依旧调用带参构造函数

    s3 = s1; //对象s3已初始化,会调用拷贝赋值函数

    func3(static_cast<CMyString&&> (s1) );
    s1.print();

    cout << "now comes to the destructor part:" << endl;
}

void test1() {
    CMyString s4 = "78";
    std::vector<CMyString> v1;
    //v1.push_back(s4);
    v1.push_back(std::move(s4)); // 对象尚未初始化,会调用移动构造函数

    std::cout << "v1 vector-container list:\n";
    for (auto& str : v1)
        str.print();

    std::vector<CMyString> v2;
    v2 = std::move(v1);

    std::cout << "v1 content:\n";
    for (auto& str : v1)
        str.print();

    std::cout << "v2 content:\n";
    for (auto& str : v2)
        str.print();
}

void test2() {

    CMyString s5 = "9";
    s5 = func2(); // 对象s5已初始化, 会产生临时对象,调用移动赋值函数
}

int main(void)
{
    std::cout << "begin test0()" << std::endl;
    test0();
    std::cout << std::endl;

    std::cout << "begin test1()" << std::endl;
    test1();
    std::cout << std::endl;

    std::cout << "begin test2()" << std::endl;
    test2();

    return 0;
}

这里写图片描述
这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值