1.构造函数和析构函数是什么
1.1构造函数
通常一个类,其内部包含有变量和函数,当我们想要使用类的时候,总是会不得不面临这样一个问题,需要对类进行初始化,否则内部这些变量就会是随机值,导致程序出现异常。
为此,我们需要在使用类之前对它进行初始化,C++就提供了这样一类特殊的函数——构造函数,它在创建类的时候会被自动调用,对类进行初始化。
1.2析构函数
析构函数和构造函数类似,它会在类对象被销毁时自动调用,主要负责一些清理工作。通常在函数结束后,在当前函数内生成的那些类就会被调用。
如果构造函数没有使用new来创建堆内存对象的话,一般是不需要析构函数做任何处理的,否则需要在析构函数内使用delete来释放这些堆内存,以避免出现内存泄漏的风险。
2.构造函数
2.1.基本形式
举个例子,测试类当中有三个变量a、b、c需要初始化,可以这样写。
class test { public: test(int a, int b, int c = 0) : m_a(a),m_b(b),m_c(c) { m_a = 100; //return; 错误,构造函数不允许return } void display() { cout << m_a << " " << m_b << " " << m_c << endl; } private: int m_a; // m_a = 1,再次赋值,m_a = 100 int m_b; // m_b = 2 int m_c; // m_c没有输入,默认 = 0 }; //初始化并输出 test t(1,2): t.display();
基本格式是 classname() : {} 或 classname() {}
由以下几个特征:
1.没有返回类型,同时也不能有返回值;
2.括号()中间是函数的输入变量,可以在后面赋值,这样输入就会在没有输入的情况下赋默认值(这一条适用于所有函数,但是必须保证默认赋值变量的顺序是从后往前);
3.冒号:后面的内容是初始化列表,使用A(B)的方式,将B赋值给A,用逗号,隔开,但最后一个变量不能有逗号,这段内容写在()和{}中间。需要注意的是,初始化列表不是必须的,可以完全不使用初始化列表,全部都在{}内赋值也可以。
4.花括号{}中间的内容,就像正常的函数实现一样,在初始化时,会执行一次内部的程序。
因此,最后输出的结果如注释写的那样:m_a = 100, m_b = 2, m_c = 0。
2.2.特殊构造函数
构造函数是运行重载的,下面这些构造函数本质和其它构造函数没有任何区别,只是这些用法比较多,从而有了一些特殊的名称而已。
默认构造函数:
当我们没有写任何构造函数的时候,系统也会隐含存在一个构造函数,只不过它的输入变量、初始化列表,以及函数内容都是空的,不进行任何初始化操作。如果我们写一个构造函数不带任何输入,那么就会覆盖掉默认的构造函数,使用人工编写的构造函数。
class test { public: //默认构造函数,就算不写出来,程序也会默认附带这样一个构造函数 test() {} private: int m_a; }; //初始化 test t;
拷贝构造函数:
以相同的类来作为当前类的唯一输入的构造函数。这里有两个关键点,相同的类和唯一输入,说大白话就是,将同样的类A拷贝到B。至于如何进行初始化,那就要针对不同的类来考虑了,通常都需要手动对类的内部变量进行一一拷贝赋值。
class test { public: test(const test& other) //将other中的所有值赋值给当前类 : m_a(other.m_a) m_b(other.m_b) {} private: int m_a; int m_b; }; //初始化 test t1; test t2(t1);
转换构造函数:
和拷贝构造函数类似,只不过是将另外一个类,转化为当前类,那么情况就更为复杂,需要依据使用场景和类的具体内容,进行初始化赋值。
例如这个例子,需要用test_a给test_b赋值,但是又无法访问a的私有成员,就需要使用get_a函数,且我们不希望更改test_a的内容加上了const,但是赋值时又需要去掉const,从而使用const_cast修饰。
class test_a { public: test_a(int a) : m_a(a) {} const int get_a() { return m_a; } private: int m_a; }; class test_b { test_b(const test_a& t) : m_b(const_cast<test_a&>(t).get_a()) {} private: int m_b; }; test_a ta(1); test_b tb(ta);
3.析构函数
class test { public: test() { } ~test() { } };
基本格式是 ~classname() {}
由以下几个特征:
1.没有返回类型,同时也不能有返回值;
2.类名前面需要加一个~,代表析构函数名;
3.花括号{}中间的内容,就像正常的函数实现一样,在类被销毁时,会执行一次内部的程序。
注意:通常情况下,我们不会主动调用析构函数,都是让系统自动去调用。
析构函数使用场景一般像下面这样,用于释放构造时占用的堆内存:
class test{ public: test() : m_p(new int) {} ~test() { delete m_p; } private: int* m_p; }
4.特殊情况
上面的情况都只适用于常规的情况,在某些特殊场景下,有些特殊操作,包括:
const类成员、static类成员、explicit显式构造、private构造函数、private析构函数等,下一期在对这些特殊情况进行说明,
标签:初始化,const,函数,int,C++,test,构造函数,07 From: https://www.cnblogs.com/wyqmx/p/17602085.html