目录
生存周期:
1. 对于全局对象,程序一开始,其构造函数就先被执行(比程序进入点更早);程序即将结束前其析构函数将被执行。
2. 对于局部对象,当对象诞生时,其构造函数被执行;当程序流程将离开该对象的声明周期时,其析构函数被执行。
3. 对于静态(static)对象,当对象诞生时其构造函数被执行;当程序将结束时其析构函数才被执行,但比全局对象的析构函数早一步执行。
4. 对于以new方式产生出来的局部对象,当对象诞生时其构造函数被执行,析构函数则在对象被delete时执行时执行
类类型的返回值:
无论多少字节,都是由临时对象带出来。
临时对象的生存周期:遇到表达式结束(在表达式之后)
#include <iostream>
using namespace std;
class Test
{
public:
Test(int a=5, int b=5):ma(a), mb(b)
{
cout<<"Test(int, int)"<<endl;
}
~Test()
{
cout<<"~Test()"<<endl;
}
Test(const Test &src):ma(src.ma), mb(src.mb)
{
cout<<"Test(const Test&)"<<endl;
}
void operator=(const Test &src)
{
ma = src.ma;
mb = src.mb;
cout<<"operator="<<endl;
}
private:
int ma;
int mb;
};
Test t1(10, 10);//程序运行时开辟,程序结束时销毁
int main()
{
Test t2(20, 20);//调用带两个参数的构造函数(从调用点到main函数结束)
Test t3=t2;//调用拷贝构造函数
t2 = t3;//调用赋值运算符重载函数
static Test t4 = Test(30, 30);//调用拷贝构造函数
t2 = Test(40, 40);//调用构造函数构造临时对象 赋值运算符的重载函数 析构函数
t2 = (Test)(50, 50);//强转相当于逗号表达式 :等价于t2=(Test)50;调用调用构造函数构造临时对象 调用赋值运算符的重载函数 析构函数
t2 = 60;//隐式生成临时对象 构造函数 赋值运算符的重载函数 析构函数
Test *p1 = new Test(70, 70);//产生内存 调用构造函数(在堆上开辟内存,需要手动释放,调用delete(否则会产生内存泄漏))
Test *p2 = new Test[2];//产生内存 构造函数
Test *p3 = &Test(80, 80);//构造函数 析构函数(显式生成临时对象)
Test &p4 = Test(90, 90);//构造函数
//引用提升临时对象的生存周期,不会销毁,因为临时对象的生存周期没有到
delete p1;//析构函数
delete []p2;//析构函数
}
Test t5(100, 100);//构造函数
初始化列表:
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。
struct和类的区别:
struct是公有的;
类只有在public中为公有,其余为private。
构造函数的初始化列表的执行顺序和成员变量的声明有关。
class CExample {
public:
int a;
float b;
//构造函数初始化列表
CExample(): a(0),b(8.8)
{}
//构造函数内部赋值
CExample()
{
a=0;
b=8.8;
}
};
成员对象:const 、引用、static、explicit、mutable
explicit:禁止隐式生成对象
mutable:去除常性。
static修饰成员变量,不属于对象私有,属于对象共享,一定在类外进行初始化
修饰成员方法,没有this指针
class example
{
public :
explicit Test(int a,int b = 0):ma(a),mb(b)//禁止隐式生成对象
void ChangeSecondMember()const
{
mb = 20;
}
this->mb = 20;
private:
int ma;
mutable int mb;//去除常性后,mb可修改
};
成员方法的调用
普通的成员方法的调用(依赖对象的调用)
静态的成员方法不能调用普通的成员方法
常对象只能调动常方法 ,不能调用普通的成员方法。
普通对象还可以调用常方法
常方法中不能调动普通的成员方法
普通的成员方法中可以调用常方法
常对象:
常对象必须在定义对象时就指定对象为常对象。
常对象中的数据成员为常变量且必须要有初始值,如
const Test test1(10,20)
凡希望保证数据成员不被改变的对象,可以声明为常对象。
常对象只能调动常方法
#include<iostream>
using namespace std;
class Test
{
public:
Test(int a, int b):mb(b)
{
ma = a;
//mb = b;
}
void Show()const//此时是一个常方法
{
cout << "ma:" << ma << endl;
cout << "mb:" << mb << endl;
}
private:
int ma;
const int mb;
};
int main()
{
const Test test1(10,20);//常对象
test1.Show();
return 0;
}
void Show()const 加const 此时Show是一个常方法
常方法:this类型: const Test* const
相当于 const Test* const this=&test1;
此时 *this被const修饰,没有被间接修改的风险,编译器允许通过。
不能调用普通的成员方法。
void Show()const//常方法
{
cout << "ma:" << ma << endl;
cout << "mb:" << mb << endl;
/**错误**/
//Show(ma);
//this->Show(ma); // 常方法this指针类型 const Test* const
(*this).Show(ma);//左边是常对象,常对象不能调用普通方法
}
void Show(int a)
{
cout << "ma:" << ma << endl;
cout << "mb:" << mb << endl;
}
常方法里面的this指针指向的是常对象,常对象不能调用普通方法。
普通对象可以调用常方法
int main()
{
Test test2(10,20);
test2.Show();//普通对象可以调用常方法
return 0;
}
Test test2(10,20);//普通对象
test2.Show();
这里相当于:const Test* const this=&test2;
普通方法可以调用常方法
void Show()const//常方法
{
cout << "ma:" << ma << endl;
cout << "mb:" << mb << endl;
}
void Show(int a)//普通成员方法
{
cout << "ma:" << ma << endl;
cout << "mb:" << mb << endl;
(*this).Show();
}
总结:
常函数,可以理解为将this换了一种修饰方式:this指针只能一直指向当前对象,相当于 Test * const this;,常函数就可以理解为cosnt Test * const this;
#include<iostream>
using namespace std;
class Test
{
public:
void change()
{
m_a = 99;
cout << "change函数" << endl;
}
void showinfo() const //使用const修饰,使得这个函数变为常函数
{
//m_a = 99; //常函数不可以修改
m_b = 99; //常函数可以修改mutable修饰的成员变量
cout << "常函数" << endl;
}
private:
int m_a;
mutable int m_b; //就算是常函数也可以进行修改
};
int main()
{
Test p1;
const Test p2; //常对象
p1.change();
//p2.change(); //常对象不可以调用普通函数
p2.showinfo();// 常对象可以调用常函数
return 0;
}