C++对象的初始化和清理

作用:对象的初始化和清理

1.构造函数  

     进行初始化操作,没有返回值,不用写void,
     函数名与类名相同
     构造函数可以有参数,可以发生重载啊
     创建对象的时候,构造函数会自动调用 , 而且只会调用一次 

2.析构函数

     进行清理操作
     没有返回值 不写void
     函数名和类名相同  在名称前面加~  
     析构函数不可以有参数 不可以发生重载 
     对象在销毁钱会自动调用析构函数 而且只会调用一次 

class person
{
	
	public:
	 person()
	 {
	 	cout <<"person构造函数的调用" << endl; 
	 } 
	 //2.析构函数 
	 ~person()
	 {
	 	cout << "person的析构函数调用" << endl; 
     } 
};
//构造和析构都是必须有的实现,如果我们自己不 提供,编译器会提供 一个空实现的构造和析构 

3.构造函数的分类及其调用

       构造函数的分类

         按照参数分类:有参构造和无参构造(默认构造)。 
         按照类型分类:普通构造和拷贝构造函数

class person
{

public: 
  person()
  {
  	cout << "无参构造函数的调用" << endl; 
  }	

   person(int a)
  {
  	age = a;
  	cout << "有参构造函数的调用" << endl; 
  }	

  //拷贝构造函数
  person(const person &p)//不能改变原来的数据 
  {
  	//将传入的人身上所有的属性,拷贝到我身上 
  	age = p.age;
   } 

  ~person()
	  {
	  	cout << "析构函数的调用" << endl; 
	  }
	  int age; 
 };
 构造函数的调用
     1.括号法

person p1; //调用默认构造函数 

 person p2(10);//有参构造函数调用 
person p3(p2);//拷贝构造函数 

 注意:1.调用默认构造函数的时候,不要加(),因为编译器会认为下面这行代码是一个函数的声明,不是创建对象 
 person p1();
 void func(); 

      2.显示法

 person p5 = person(10); //有参构造 
 person p6 = person(p5);//拷贝构造

 person(10);//匿名对象,等号左边是名字 当前执行结束后,系统会自动回收掉匿名对象
        
        
  注意:2.不要 利用拷贝构造函数初始化匿名对象,编译器会认为是一个对象的声明 
       //person p6 = p6; 
        person (p6); //错误的

     3.隐式转换法 

   person p7 = 10;
      //相当于写了person p7 = person(10) 
     person p8 = p7;//拷贝构造 

4.拷贝构造函数调用时机

1.使用一个已经创建完毕的对象来初始化一个新对象

void text01()
{
    person p1(10);
    person p2(p1); 
}

2.值传递的方式给函数参数传值

void dowork(person p)
{
}

void text02()
{
    person p;
    dowork(p);
 } 

3.以值方式返回局部对象

person dowork2()
{
    person p1;
    cout << (int*)&p1 << endl; //局部变量,执行完之后被释放。 
    return p1;
}

void text03()
{
    person p = dowork2();
    cout << (int*)&p << endl;
}

5.构造函数的调用规则

默认情况下,C++编译器至少给一个类添加三个函数

1.默认构造函数(无参,函数体为空)

2.默认析构函数(无参,函数体为空)

3.默认拷贝构造函数(对属性进行值拷贝)

构造函数调用规则

1.如果我们写了有参构造函数,那么编译器就不再提供默认构造函数,仍然提供拷贝构造函数

2.如果我们写了拷贝构造函数,那么编译器就不再提供普通构造函数(默认构造函数)

6.深拷贝与浅拷贝

浅拷贝:简单的赋值拷贝(等号赋值操作,利用编译器提供的拷贝析构函数)

深拷贝:在堆区重新申请空间,进行拷贝操作

注意:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题(重复释放堆空间(非法操作))

#include<iostream>
using namespace std;
class person
{
    public:
    	   person()
    	   {
    	   	cout << "默认构造函数的调用" << endl; 
		   }
		   person(int age,int height)
		   {
		   	m_age = age;
		   	m_height = new int(height);//堆区 
		   	cout << "有参构造函数调用" << endl; 
		   }
		   person(const person &p)
		   {
		   	   cout << "person 拷贝构造函数调用" << endl;
		   	   //浅拷贝
				  //m_height = p.m_height ; 
				  //深拷贝操作
				  m_age = p.m_age ;
				  m_height = new int(*p.m_height ); 
		   }
		   ~person()
		   {//析构代码,将堆区开辟数据做释放操作 
		   if(m_height != NULL)
		   {
		    	delete m_height;
		    	m_height = NULL;
			} 
		   	cout << "析构函数调用" << endl; 
		   }
	int m_age;	
	int *m_height;
};
void test01()
{
	person p1(18,160);//在栈区,后进先出,所以p2先被释放 
	cout << "p1的年龄为:" << p1.m_age << "p1身高:" << *p1.m_height  << endl; 
	person p2(p1);
	cout << "p2的年龄:" << p2.m_age << "p2身高:" << *p2.m_height  << endl;
}
int main()
{
	test01();
	return 0;
} 

若使用编译器提供的拷贝构造函数,则可能会造成堆空间的重复释放

7.初始化列表

c++提供的初始化列表语法,用来初始化属性

语法:构造函数():属性1(值1),属性2(值2)......{ }

#include<iostream>
using namespace std;
//初始化列表 
class person
{
public:
//传统初始化操作 
//    person(int a,int b,int c)
//    {
//    	m_a = a;
//    	m_b = b;
//    	m_c = c;
//	}
//初始化列表初始化属性
person(int a,int b,int c):m_a(a),m_b(b),m_c(c) 
{
	
}
	int m_a;
	int m_b;
	int m_c; 
    
};
void test01()
{
	person p(10,20,30);
	cout << "m_a = " << p.m_a << endl;
	cout << "m_b = " << p.m_b << endl;
	cout << "m_c = " << p.m_c << endl;
 } 
int main()
{
	test01();
}

8.类对象作为类成员

c++类中的成员可以是了另一个类的对象,我们称该成员为对象成员

当类对象做为本类成员,构造时候先构造其他类对象,再构造自身

析构的顺序?

先释放自身,再释放其他类对象

#include<iostream>
#include<string>
using namespace std;
class phone
{
public:
	phone(string pname)
	{
		m_pname = pname;
	}
	//爪机品牌名称 
	string m_pname; 
};
class person
{
public:
	//姓名
	person(string name,string pname):m_name(name),m_phone(pname) 	
	{
		
	}
	string m_name;
	//手机 
	phone m_phone; 
};
void test01()
{
	person p("张三","苹果max"); 
	cout << "姓名" <<  p.m_name << endl;
	cout << "爪机" << p.m_phone.m_pname  << endl; 
} 
int main()
{
	test01();
	return 0; 
}

9.静态成员

在成员变量和成员函数前面加上关键字static ,称为静态成员

静态成员分类
1.静态成员变量

    注意事项:

          1.所有对象共享同一份数据,一个改了其他人看到的数据也改了

           2.在编译阶段分配内存,生成.exe程序还没有运行之前,就已经分配好内存了

           3.类内声明,类外初始化

           4.静态成员变量也是有访问权限的

           5.访问方式有两种

               (1)通过对象进行访问

               (2)通过域名进行访问

#include<iostream>
#include<string>
using namespace std;
class person{
	public:
		//所有对象都共享同一份数据
		//编译阶段分配内存,
		//类内声明,类外初始化 
		//访问权限 
		static int m_a;
		
	private://出了这个类,类外是不可以访问的 
	    static int m_b; 
	
};
//int m_a = 100;//全局变量

int person::m_a = 100;//person 作用域下的m_a;
int person::m_b = 200;
 
void test01()
{
	person p;
	cout << p.m_a << endl;//100
	
	person p2;
	p2.m_a  = 200;
	cout << p.m_a << endl;//200
 } 
 void test02()
 {
 	//静态成员变量不属于某个对象,所有对象共享同一份数据
	  //因此静态成员变量有两种访问方式
	  //1. 通过对象进行访问
	  person p;
	  cout << p.m_a << endl;
	  //2.通过域名进行访问
	   cout << person ::m_a << endl; 
	   //cout << person::m_b<< endl;
	   //private 不可以被访问 
 }
int main()
{
	//test01();
	test02();
}
2.静态成员函数

           注意事项:

                        1.所有对象共享同一个函数

                        2.静态成员函数只能访问静态成员变量

                        3.静态成员含漱液的访问权限(类外访问不到私有的静态成员函数)

#include<iostream>
#include<string>
using namespace std;
 //静态成员函数
 //所有对象共享同一个函数 
 //静态成员函数只能访问静态成员变量 
class person{
	public:
		//静态成员函数
		static void func()
		{
			m_a = 200;//静态成员函数可以访问静态成员变量 
			m_b = 300;//报错,静态成员函数不能访问非静态成员变量 
			//m_b必须通过一个对象才能访问这块内存,如果有多个对象,无法区分到底是给哪个对象的m_b赋值 
			cout << "static void func调用" << endl; 
		 } 
		 static int m_a;//静态成员变量 (类内声明,类外初始化) 
                int m_b;
        //静态成员函数的访问权限
    private://类外访问不到私有 的静态成员函数 
	    static void func2()
		{
			cout << "static void func2调用" << endl; 
		} 
};
int person :: m_a  = 100; 
void test01()
{
	//1.对象
	person p;
	p.func(); 
	//2.类名 
	person::func ();
	//cout <<  person :: m_a << endl;
}
int main()
{
	test01();
 } 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值