欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

c++-构造函数

程序员文章站 2023-11-09 18:21:28
构造函数 + 构造和析构概念语法 + 构造函数的分类 + 有参构造函数3种调用方法 + 拷贝构造函数4种调用时机 场景1和2:A a(b); A a = b; 场景3:形参是一个元素,实参传递给形参 场景4:函数返回值返回一个元素,匿名对象 匿名对象的去和留 对象的初始化 和 对象的=操作 是两个不 ......

构造函数

  • 构造和析构概念语法
  • 构造函数的分类
  • 有参构造函数3种调用方法
  • 拷贝构造函数4种调用时机
    • 场景1和2:a a(b); a a = b;
    • 场景3:形参是一个元素,实参传递给形参
    • 场景4:函数返回值返回一个元素,匿名对象
    • 匿名对象的去和留
    • 对象的初始化 和 对象的=操作 是两个不同的概念
  • 构造和析构
    • 构造和析构概念语法
    • 构造函数的分类
    • 有参构造函数3种调用方法
    • 拷贝构造函数4种调用时机
      • 场景1和2:a a(b); a a = b;
      • 场景3:形参是一个元素,实参传递给形参
      • 场景4:函数返回值返回一个元素,匿名对象
      • 匿名对象的去和留
      • 对象的初始化 和 对象的=操作 是两个不同的概念
    • 构造函数调用规则研究(写了构造函数则必须调用)
    • 多个对象的构造 构造函数初始化列表
    • 构造函数和析构函数的调用顺序(先组合对象的构造、自己构造;析构和构造相反)
    • 深拷贝和浅拷贝
      • 问题抛出 显示的编写拷贝构造函数
      • 默认的=号操作 也是浅拷贝,解决方案重载=操作符
      • 总结:c++编译给提供的默认的拷贝构造和=操作都是浅拷贝
    • 构造和析构综合练习
      • 匿名对象:直接调用构造函数
      • 匿名对象:构造中调用构造
  • 构造函数调用规则研究(写了构造函数则必须调用)
  • 多个对象的构造 构造函数初始化列表
  • 构造函数和析构函数的调用顺序(先组合对象的构造、自己构造;析构和构造相反)
  • 深拷贝和浅拷贝
    • 问题抛出 显示的编写拷贝构造函数
    • 默认的=号操作 也是浅拷贝,解决方案重载=操作符
    • 总结:c++编译给提供的默认的拷贝构造和=操作都是浅拷贝
#define _crt_secure_no_warnings
#include <iostream>
#include <string.h>


using namespace std;

class test
{
public:
#if 0
    void init(int x, int y)
    {
        m_x = x;
        m_y = y;
    }
#endif

    //test类的构造函数
    //在对象被创建的时候,用来初始化对象的函数
    test()//无参数的构造函数
    {
        m_x = 0;
        m_y = 0;
    }
    test(int x, int y)
    {
        m_x = x;
        m_y = y;
        // name = (char*)malloc(100);
        strcpy(name, "zhang3");
    }
    test(int x)
    {
        m_x = x;
        m_y = 0;
    }

    void printt()
    {
        cout << "x = " << m_x << "  y = " << m_y << endl;
    }


    //析构函数和构造函数都没有返回值,
    //析构函数没有形参
    ~test() {
        cout << "~test()...." << endl;
        if (name != null) {
            // free(name);
            cout << "free succ!" << endl;
        }
    }
private:
    int m_x;
    int m_y;
    char *name;
};

void test1()
{
    test t1(10, 20);
    t1.printt();

    //在一个对象临死之前,要自定调用析构函数
}

int main(void)
{
#if 0
    test t1(10, 20);
    t1.printt();
    //t1.init(10, 20);

    test t2(100);
    t2.printt();

    test t3;//就是调用类的无参数构造函数

    t3.printt();

#endif

    test1();
    return 0;
}

拷贝构造函数

#define _crt_secure_no_warnings
#include <iostream>


using namespace std;

class test
{
public:
    test()
    {
        m_x = 0;
        m_y = 0;
    }
    test(int x, int y)
    {
        m_x = x;
        m_y = y;
    }

    void printt()
    {
        cout << "x =" << m_x << ", y = " << m_y << endl;
    }

#if 1
    //显示的拷贝构造函数
    test(const test &another)
    {
        cout << "test(const test &)..." << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }
#endif
#if 0
    //? 会有一个默认的拷贝构造函数
    test(const test &another)
    {
        m_x = another.m_x;
        m_y = another.m_y;
    }
#endif

    //=赋值操作符
    void operator=(const test &another)
    {
        m_x = another.m_x;
        m_y = another.m_y;
    }
private:
    int m_x;
    int m_y;
};

int main(void)
{
    test t1(100, 200); 

    test t2(t1); 

    t2.printt();



    //构造函数是对象初始化的时候调用
    test t3; //依然是初始化t3的时候调用t3构造函数,依然是调用t3的拷贝构造函数

    t3 = t1; //调用的不是t3拷贝构造函数,而是t3的赋值操作符函数

    return 0;
}

默认的构造函数和解析构造函数

#define _crt_secure_no_warnings
#include <iostream>


using namespace std;

class test
{
public:
    //默认的无参构造函数
#if 0
    test()
    {

    }
#endif
    //显示提供一个有参数的构造函数,默认的构造函数就不复存在
    test(int x, int y)
    {
        m_x = x;
        m_y = y;
    }
    test() {
        m_x = 0;
        m_y = 0;
    }

    void printt()
    {
        cout << "x = " << m_x << "  y = " << m_y << endl;
    }

    //默认的析构函数
#if 0
    ~test()
    {

    }
#endif
    ~test() {
        cout << "~test()..." << endl;
    }


private:
    int m_x;
    int m_y;
};

int main(void)
{
    test t1;//调用test无参构造
    t1.printt();
    
    return 0;
}

默认的拷贝构造函数

  • 类中 会有个默认的无参构造函数:

当没有任何显示的构造函数(显示的无参构,显示有参,显示拷贝构造) 的时候,默认无参构造函数就会出现。

  • 会有默认的拷贝构造函数:
    -->当没有 显示的拷贝构造 * 的函数,默认的拷贝构造就会出现。

  • 会有默认的析构函数
    --> 当没有显示的析构函数的时候, 默认的析构函数就会出现

#define _crt_secure_no_warnings
#include <iostream>

using namespace std;

class a
{
public:
#if 0
    a()
    {
        
    }
#endif
#if 0
    a(const a &another)
    {
        m_a = another.m_a;
        m_b = another.m_b;
    }
#endif
    a()
    {

    }
    a(int a, int b)
    {

    }
#if 0
    ~a()
    {

    }
#endif
    ~a()
    {
        cout << "~a()" << endl;
    }
private:
    int m_a;
    int m_b;
};

//类中 会有个默认的无参构造函数:  、
//      -->当没有任何***显示的构造函数(显示的无参构,显示有参,显示拷贝构造)*** 的时候,默认无参构造函数就会出现。

//      会有默认的拷贝构造函数:
//      -->当没有 **显示的拷贝构造 ***  的函数,默认的拷贝构造就会出现。

//     会有默认的析构函数
//      --> 当没有***显示的析构函数***的时候,  默认的析构函数就会出现。


int main(void)
{
    a a;
    
    a a1(a);
    
    return 0;
}

拷贝构造函数的应用场景

#define _crt_secure_no_warnings
#include <iostream>

using namespace std;

class test
{
public:
    test()
    {
        cout << "test()..." << endl;
        m_x = 0;
        m_y = 0;
    }
    test(int x, int y)
    {
        cout << "test(int x, int y)..." << endl;

        m_x = x;
        m_y = y;
    }
    test(const test & another)
    {
        cout << "test(const test &)..." << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void operator=(const test &another)
    {
        cout << "operatoer = (const test &)" << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void printt() {
        cout << "x = " << m_x << ", m_y = " << m_y << endl;
    }

    ~test() {
        cout << "~test()..." << endl;
    }
private:
    int m_x;
    int m_y;
};


//析构函数调用的顺序, 跟构造相反, 谁先构造的,谁后析构。
//场景1
void test1()
{
    test t1(10, 20);
    test t2(t1);//test t2 = t1;
}

//场景2
void test2()
{
    test t1(10, 20);
    test t2;

    t2 = t1;//=操作符
}


void func(test t)//test t = t1; //test t 的拷贝构造函数
{
    cout << "func begin..." << endl;
    t.printt();
    cout << "func end..." << endl;
}

//场景3
void test3()
{
    cout << "test3 begin..." << endl;
    test t1(10, 20);

    func(t1);

    cout << "test3 end..." << endl;
}


//场景4
test func2()
{
    cout << "func2 begin..." << endl;
    test temp(10, 20);
    temp.printt();

    cout << "func2 end..." << endl;

    return temp;
}//匿名的对象 = temp  匿名对象.拷贝构造(temp)

void test4()
{
    cout << "test4 being.. " << endl;
    func2();// 返回一个匿名对象。 当一个函数返回一个匿名对象的时候,函数外部没有任何
            //变量去接收它, 这个匿名对象将不会再被使用,(找不到), 编译会直接将个这个匿名对象
            //回收掉,而不是等待整改函数执行完毕再回收.
    //匿名对象就被回收。
    
    cout << "test4 end" << endl;
}

void test5()
{
    cout << "test 5begin.. " << endl;
    test t1 = func2(); //会不会触发t1拷贝构造来   t1.拷贝(匿名)?
                        //并不会触发t1拷贝,而是 将匿名对象转正 t1,
                        //把这个匿名对象 起了名字就叫t1.

    cout << "test 5 end.." << endl;
}

//场景6
void test6()
{
    cout << "test6 begin..." << endl;
    test t1;//t1已经被初始化了。

    t1 = func2(); //t1已经被初始化了,所以func2返回的匿名对象不会再次转正,而依然是匿名对象。
                    //所以t1会调用等号操作符,t1.operator=(匿名对象), 然后编译器会立刻回收掉匿名对象

    t1.printt();

    cout << "test6 end.." << endl;
}


int main(void)
{
    //test1();
    //test2();
    //test3();
    //test4();
    //test5();
    test6();

    return 0;
}

深拷贝和浅拷贝

#define _crt_secure_no_warnings
#include <iostream>

using namespace std;

class test
{
public:
    test()
    {
        cout << "test()..." << endl;
        m_x = 0;
        m_y = 0;
    }
    test(int x, int y)
    {
        cout << "test(int x, int y)..." << endl;

        m_x = x;
        m_y = y;
    }
    test(const test & another)
    {
        cout << "test(const test &)..." << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void operator=(const test &another)
    {
        cout << "operatoer = (const test &)" << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void printt() {
        cout << "x = " << m_x << ", m_y = " << m_y << endl;
    }

    ~test() {
        cout << "~test()..." << endl;
    }
private:
    int m_x;
    int m_y;
};


//析构函数调用的顺序, 跟构造相反, 谁先构造的,谁后析构。
//场景1
void test1()
{
    test t1(10, 20);
    test t2(t1);//test t2 = t1;
}

//场景2
void test2()
{
    test t1(10, 20);
    test t2;

    t2 = t1;//=操作符
}


void func(test t)//test t = t1; //test t 的拷贝构造函数
{
    cout << "func begin..." << endl;
    t.printt();
    cout << "func end..." << endl;
}

//场景3
void test3()
{
    cout << "test3 begin..." << endl;
    test t1(10, 20);

    func(t1);

    cout << "test3 end..." << endl;
}


//场景4
test func2()
{
    cout << "func2 begin..." << endl;
    test temp(10, 20);
    temp.printt();

    cout << "func2 end..." << endl;

    return temp;
}//匿名的对象 = temp  匿名对象.拷贝构造(temp)

void test4()
{
    cout << "test4 being.. " << endl;
    func2();// 返回一个匿名对象。 当一个函数返回一个匿名对象的时候,函数外部没有任何
            //变量去接收它, 这个匿名对象将不会再被使用,(找不到), 编译会直接将个这个匿名对象
            //回收掉,而不是等待整改函数执行完毕再回收.
    //匿名对象就被回收。
    
    cout << "test4 end" << endl;
}

void test5()
{
    cout << "test 5begin.. " << endl;
    test t1 = func2(); //会不会触发t1拷贝构造来   t1.拷贝(匿名)?
                        //并不会触发t1拷贝,而是 将匿名对象转正 t1,
                        //把这个匿名对象 起了名字就叫t1.

    cout << "test 5 end.." << endl;
}

//场景6
void test6()
{
    cout << "test6 begin..." << endl;
    test t1;//t1已经被初始化了。

    t1 = func2(); //t1已经被初始化了,所以func2返回的匿名对象不会再次转正,而依然是匿名对象。
                    //所以t1会调用等号操作符,t1.operator=(匿名对象), 然后编译器会立刻回收掉匿名对象

    t1.printt();

    cout << "test6 end.." << endl;
}


int main(void)
{
    //test1();
    //test2();
    //test3();
    //test4();
    //test5();
    test6();

    return 0;
}

构造函数的初始化列表

#define _crt_secure_no_warnings
#include <iostream>

using namespace std;

class test
{
public:
    test()
    {
        cout << "test()..." << endl;
        m_x = 0;
        m_y = 0;
    }
    test(int x, int y)
    {
        cout << "test(int x, int y)..." << endl;

        m_x = x;
        m_y = y;
    }
    test(const test & another)
    {
        cout << "test(const test &)..." << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void operator=(const test &another)
    {
        cout << "operatoer = (const test &)" << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void printt() {
        cout << "x = " << m_x << ", m_y = " << m_y << endl;
    }

    ~test() {
        cout << "~test()..." << endl;
    }
private:
    int m_x;
    int m_y;
};


//析构函数调用的顺序, 跟构造相反, 谁先构造的,谁后析构。
//场景1
void test1()
{
    test t1(10, 20);
    test t2(t1);//test t2 = t1;
}

//场景2
void test2()
{
    test t1(10, 20);
    test t2;

    t2 = t1;//=操作符
}


void func(test t)//test t = t1; //test t 的拷贝构造函数
{
    cout << "func begin..." << endl;
    t.printt();
    cout << "func end..." << endl;
}

//场景3
void test3()
{
    cout << "test3 begin..." << endl;
    test t1(10, 20);

    func(t1);

    cout << "test3 end..." << endl;
}


//场景4
test func2()
{
    cout << "func2 begin..." << endl;
    test temp(10, 20);
    temp.printt();

    cout << "func2 end..." << endl;

    return temp;
}//匿名的对象 = temp  匿名对象.拷贝构造(temp)

void test4()
{
    cout << "test4 being.. " << endl;
    func2();// 返回一个匿名对象。 当一个函数返回一个匿名对象的时候,函数外部没有任何
            //变量去接收它, 这个匿名对象将不会再被使用,(找不到), 编译会直接将个这个匿名对象
            //回收掉,而不是等待整改函数执行完毕再回收.
    //匿名对象就被回收。
    
    cout << "test4 end" << endl;
}

void test5()
{
    cout << "test 5begin.. " << endl;
    test t1 = func2(); //会不会触发t1拷贝构造来   t1.拷贝(匿名)?
                        //并不会触发t1拷贝,而是 将匿名对象转正 t1,
                        //把这个匿名对象 起了名字就叫t1.

    cout << "test 5 end.." << endl;
}

//场景6
void test6()
{
    cout << "test6 begin..." << endl;
    test t1;//t1已经被初始化了。

    t1 = func2(); //t1已经被初始化了,所以func2返回的匿名对象不会再次转正,而依然是匿名对象。
                    //所以t1会调用等号操作符,t1.operator=(匿名对象), 然后编译器会立刻回收掉匿名对象

    t1.printt();

    cout << "test6 end.." << endl;
}


int main(void)
{
    //test1();
    //test2();
    //test3();
    //test4();
    //test5();
    test6();

    return 0;
}