day03 C++学习

对象的构造与析构

创建一个对象时,常常需要作某些初始化的工作,例如对数据成员赋初值。注意,类的数据成员是不能在声明类时初始化的。
为了解决这个问题,C++编译器提供了构造函数(constructor)来处理对象的初始化。构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行

1.1类的构造和解析基础

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>
using namespace std;

class Test
{
public:
	Test()  //无参数 构造函数
	{
		a = 10;  //作用完成对属性的初始化工作
		p = (char *)malloc(100);
		strcpy(p, "aaaaffff");
		cout<<"我是构造函数 被执行了"<<endl;
	}
	void print()
	{
		cout<<p<<endl;
		cout<<a<<endl;
	}
	~Test() //析构函数
	{
		if (p != NULL)
		{
			free(p);
		}
		cout<<"我是析构函数,被调用了" <<endl;
	}
protected:
private:
	int a ;
	char *p;
};

//给对象搭建一个舞台,研究对象的行为
void objplay()
{
	//先创建的对象 后释放
	Test t1;
	t1.print();

	printf("分隔符\n");
	Test t2;
	t2.print();
}
void main11()
{
	objplay();
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

1.2类的构造和解析基础



#include <iostream>
using namespace std;

class Test2
{
public:
	Test2()  //无参数构造函数
	{
		m_a = 0;
		m_b = 0;
		cout<<"无参数构造函数"<<endl;
	}
	
	Test2(int a)
	{
		m_a = a;
		m_b = 0;
	}

	Test2(int a, int b) //有参数构造函数   //3种方法
	{
		m_a = a;
		m_b = b;
		cout<<"有参数构造函数"<<endl;
	}

	//赋值构造函数 (copy构造函数) //
	Test2(const Test2& obj )
	{
		cout<<"我也是构造函数 " <<endl;
	}

public:
	void printT()
	{
		cout<<"普通成员函数"<<endl;
	}
private:
	int m_a;
	int m_b;
};

void main21()
{
	
	Test2 t1;  //调用无参数构造函数
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

//调用 调用有参数构造函数 3
void main22()
{
	//1括号法 
	Test2 t1(1, 2);  //调用参数构造函数  c++编译器自动的调用构造函数
	t1.printT();

	// 2 =号法
	Test2 t2 = (3, 4, 5, 6, 7); // = c+对等号符 功能增强  c++编译器自动的调用构造函数

	Test2 t3 = 5;

	//3 直接调用构造函数  手动的调用构造函数
	Test2 t4 = Test2(1, 2);   //匿名对象 (匿名对象的去和留) 抛砖 ....//t4对象的初始化
	//

	t1 =  t4;  //把t4 copy给 t1  //赋值操作 
	//对象的初始化 和 对象的赋值 是两个不同的概念 
	
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

1.3 显示初始化方案


#include <iostream>
using namespace std;


class Test3
{
public:
	void init(int _a, int _b)
	{
		a = _a;
		b = _b;
	}

protected:
private:
	int a;
	int b;
};


void main31()
{
	
	//类没有提供构造函数,c++编译器会自动给你提供一个默认的构造函数
	//类没有提供构造函数 copy构造构造函数, c++编译器会自动给程序员提供一个 默认的copy构造函数  = 
	Test3 t1; 
	int a = 10; 
	int b = 20;
	t1.init(a, b);

	Test3 tArray[3];
	tArray[0].init(1, 2);
	tArray[1].init(1, 2);
	tArray[2].init(1, 2);

	//
	Test3 t21;  t21.init(1, 2);
	Test3 t22;	t22.init(1, 2);
	Test3 t23;	t23.init(1, 2);

	//在这种场景之下 显示的初始化方案 显得很蹩脚
	Test3 tArray2[3] = {t21, t22, t23};

	//在这种场景之下,满足不了,编程需要
	Test3 tArray3[1999] = {t21, t22, t23};
	

	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

1.4copy的构造函数


#include <iostream>
using namespace std;

class Test4
{
public:
	Test4()  //无参数构造函数
	{
		m_a = 0;
		m_b = 0;
		cout<<"无参数构造函数"<<endl;
	}

	Test4(int a)
	{
		m_a = a;
		m_b = 0;
	}

	Test4(int a, int b) //有参数构造函数   //3种方法
	{
		m_a = a;
		m_b = b;
		cout<<"有参数构造函数"<<endl;
	}

	//赋值构造函数 (copy构造函数) //
	Test4(const Test4& obj )
	{
		cout<<"我也是构造函数 " <<endl;
		m_b = obj.m_b + 100;
		m_a = obj.m_a + 100;
	}

public:
	void printT()
	{
		cout<<"普通成员函数"<<endl;
		cout<<"m_a"<<m_a<<" m_a"<<m_b<<endl;
	}
private:
	int m_a;
	int m_b;
};

//1  赋值构造函数 用1个对象去初始化另外一个对象  
void main41()
{
	Test4 t1(1, 2);
	Test4 t0(1, 2);

	//赋值=操作 会不会调用构造函数
	//operator=()//抛砖
	t0 = t1; //用t1 给 t0赋值  到操作 和 初始化是两个不同的概念

	//第1种调用方法
	Test4 t2 = t1; //用t1来初始化 t2 
	t2.printT();
	
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

//第二种调用时机
void main44()
{
	Test4 t1(1, 2);
	Test4 t0(1, 2);

	Test4 t2(t1);  //用t1对象 初始化 t2对象 
	t2.printT();

	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

#include <iostream>
using namespace std;


class Location 
{ 
public:
	Location( int xx = 0 , int yy = 0 ) 
	{ 
		X = xx ;  Y = yy ;  cout << "Constructor Object.\n" ; 
	}

	//copy构造函数  完成对象的初始化
	Location(const Location & obj) //copy构造函数 
	{
		X = obj.X; Y = obj.Y;
	}
	~Location() 
	{ 
		cout << X << "," << Y << " Object destroyed." << endl ; 
	}
	int  GetX () { return X ; }		int GetY () { return Y ; }
private :   int  X , Y ;
} ;


//业务函数  形参是一个元素
void f(Location p)
{
	cout<<p.GetX()<<endl;
}

void playobj()
{
	Location  a(1, 2);
	Location  b = a;
	cout<<"b对象已经初始化完毕"<<endl;

	f(b); //b实参取初始化形参p,会调用copy构造函数
}

void main51()
{
	playobj();
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}



#include <iostream>
using namespace std;


class Location 
{ 
public:
	Location( int xx = 0 , int yy = 0 ) 
	{ 
		X = xx ;  Y = yy ;  cout << "Constructor Object.\n" ; 
	}

	//copy构造函数  完成对象的初始化
	Location(const Location & obj) //copy构造函数 
	{
		X = obj.X; Y = obj.Y;
	}
	~Location() 
	{ 
		cout << X << "," << Y << " Object destroyed." << endl ; 
	}
	int  GetX () { return X ; }		int GetY () { return Y ; }
private :   int  X , Y ;
} ;

//g函数 返回一个元素 
//结论1 : 函数的返回值是一个元素 (复杂类型的), 返回的是一个新的匿名对象(所以会调用匿名对象类的copy构造函数)

//
//结论2: 有关 匿名对象的去和留
//如果用匿名对象  初始化 另外一个同类型的对象, 匿名对象 转成有名对象
//如果用匿名对象  赋值给 另外一个同类型的对象, 匿名对象 被析构

//
//你这么写代码,设计编译器的大牛们:
//我就给你返回一个新对象(没有名字 匿名对象)
Location g()
{
	Location A(1, 2);
	return A;
}

//
void objplay2()
{
	g(); 
}

//
void objplay3()
{
	//用匿名对象初始化m 此时c++编译器 直接把匿名对转成m;(扶正) 从匿名转成有名字了m
	Location m = g(); 
	printf("匿名对象,被扶正,不会析构掉\n");
	cout<<m.GetX()<<endl;;
}

void objplay4()
{
	//用匿名对象 赋值给 m2后, 匿名对象被析构
	Location m2(1, 2);
	m2 = g();
	printf("因为用匿名对象=给m2, 匿名对象,被析构\n");
	cout<<m2.GetX()<<endl;;
}
void main()
{
	//objplay2();
	//objplay3();
	objplay4();
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

1.5 构造函数调用规则的研究


#include <iostream>
using namespace std;

class Test
{
public:
	
// 	Test(const Test& obj) //copy构造函数 作用: 用一个对象初始化另外一个对象
// 	{
// 		a = obj.a + 100;
// 		b = obj.b + 100;
// 	}

// 	Test(int _a, int _b)
// 	{
// 		;
// 	}
	Test()
	{

	}
	
	void printT()
	{
		cout << "a:" << a << "b: "<<b<< endl; 
	}

protected:
private:
	int a;
	int b;
};

//当类中定义了拷贝构造函数时,c++编译器不会提供无参数构造函数
//当类中定义了有参数构造函数是,c++编译器不会提供无参数构造函数

//在定义类时, 只要你写了构造函数,则必须要用

void main81()
{
	//Test t1; //调用无参构造函数
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

1.6 深拷贝与浅拷贝


#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>
using namespace std;

//

class  Name
{
public:
	Name(const char *myp)
	{
		m_len = strlen(myp);
		m_p =(char *) malloc(m_len + 1); //
		strcpy(m_p, myp);
	}

	//Name obj2 = obj1;
	//解决方案: 手工的编写拷贝构造函数 使用深copy
	Name(const Name& obj1)
	{
		m_len = obj1.m_len;
		m_p = (char *)malloc(m_len + 1);
		strcpy(m_p, obj1.m_p);
	}

	~Name()
	{
		if (m_p != NULL)
		{
			free(m_p);
			m_p = NULL;
			m_len = 0;
		}
	}
protected:
private:
	char *m_p ;
	int m_len; 
};

//对象析构的时候 出现coredump
void objplaymain()
{
	Name obj1("abcdefg");
	//Name obj2 = obj1;  //C++编译器提供的 默认的copy构造函数  浅拷贝
	Name obj3("obj3");

	obj3 = obj1;  // C++编译器提供的 等号操作 也属 浅拷贝
}

void main91()
{
	objplaymain();
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

1.7 构造函数初始化列表


#include <iostream>
using namespace std;

class A
{
public:
	A(int _a)
	{
		a = _a;
		cout << "构造函数" << "a" << a << endl;
	}

	~A()
	{
		cout << "析构函数" << "a" << a << endl;
	}

protected:
private:
	int a;
};


//1 构造函数的初始化列表  解决: 在B类中 组合了一个 A类对象 (A类设计了构造函数)
//根据构造函数的调用规则 设计A的构造函数, 必须要用;没有机会初始化A
//新的语法  Constructor::Contructor() : m1(v1), m2(v1,v2), m3(v3)
class B
{
public:
	B(int _b1, int _b2) : a1(1), a2(2), c(0)
	{

	}

	B(int _b1, int _b2, int m, int n) : a1(m), a2(n), c(0)
	{
		b1 = _b1;
		b2 = _b2;
		cout <<"B的构造函数"<<endl;
	}
	~B()
	{
		cout<<"B的析构函数" <<endl;
	}

protected:
private:
	int b1;
	int b2;
	A a2;
	A a1;
	const int c;
};


//2 先执行 被组合对象的构造函数 
//如果组合对象有多个,按照定义顺序, 而不是按照初始化列表的顺序

//析构函数 : 和构造函数的调用顺序相反

//3 被组合对象的构造顺序 与定义顺序有关系 ,与初始化列表的顺序没有关系.
//4 初始化列表 用来 给const 属性赋值 
void obj10play()
{
	
	//A a1(10);
	//B ojbB(1, 2);

	//1参数传递 
	B ojbB2(1, 2,3, 4);

	//2 调用顺序
	
	return ;
}

void main100()
{
	obj10play();
	system("pause");
}

1.8 构造中调用构造

#include "iostream"
using namespace std;


//构造中调用构造是危险的行为
class MyTest
{
public:
	MyTest(int a, int b, int c)
	{
		this->a = a;
		this->b = b;
		this->c = c;
	}

	MyTest(int a, int b)
	{
		this->a = a;
		this->b = b;

		MyTest(a, b, 100); //产生新的匿名对象
	}
	~MyTest()
	{
		printf("MyTest~:%d, %d, %d\n", a, b, c);
	}

protected:
private:
	int a;
	int b;
	int c;

public:
	int getC() const { return c; }
	void setC(int val) { c = val; }
};

int main()
{
	MyTest t1(1, 2);
	printf("c:%d", t1.getC()); //请问c的值是?
	system("pause");
	return 0;
}

1.9 new和delete基本用法和扩展


#include <iostream>
using namespace std;

// 1
//		malloc	free				c语言的函数
//		new		delete 操作符	c++的语法

//2		new 基础类型变量  分配数组变量  分配类对象

//3		

分配基础类型
void main01()
{
	// 
	int *p = (int *)malloc(sizeof(int));
	*p = 10;
	//free(p);
	delete p;

	int *p2 = new int; //分配基础类型
	*p2 = 20;
	free(p2);
	//
	int *p3 = new int(30);
	printf("*p3:%d \n", *p3);
	//delete p3;
	free(p3);

	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

//分配数组变量
void main02()
{
	//c语言分配数组
	int *p = (int *)malloc(sizeof(int) * 10);  //int array[10];
	p[0] = 1;
	//free(p);
	delete[] p;

	//c++分配数组 
	int *pArray = new int[10] ;
	pArray[1] = 2;
	//delete [] pArray; //数组不要把[] 忘记
	free(pArray);

	char *pArray2 = new char[25] ; //char buf[25]
	delete [] pArray2;


	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

class Test
{
public:
	Test(int _a)
	{
		a = _a;
		cout<<"构造函数执行" <<endl;
	}

	~Test()
	{
		cout<<"析构函数执行" <<endl;
	}

protected:
private:
	int a;
};

//分配对象new delete
//相同 和 不同的地方 new能执行类型构造函数   delete操作符 能执行类的析构函数

//	malloc 	free函数 C
//1 new 	delete 操作符号 c++的关键字
//结论
void main()
{
	//c 
	Test *pT1 = (Test *)malloc(sizeof(Test));
	//free(pT1);
	delete pT1;

	//c++
	Test *pT2 = new Test(10);
	//delete pT2;
	free(pT2);

	cout<<"hello..."<<endl;
	system("pause");
}

1-24 今天学到这里了,明天上午有面试,加油

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值