17_C++_面向对象_构造函数_析构函数

文章目录

1.立方体案例(了解)

1.抽象立方体:属性,长宽高,方法:设置和获取属性的方法,判断两个立方体是否相等的方法

2.一个对象必须要初始化成员变量

3.成员函数中隐藏了一个本类的对象

2.点和圆的案例(了解)

1.抽象点:属性有点的坐标,方法:设置和获取坐标的方法

2.抽象圆:属性有圆心和半径,方法:设置和获取圆心的方法,设置和获取半径的方法,判断圆和点的关系的方法

3.用圆心和点之间的距离的平方,和半径的平方比较来确定之间的关系

4.三角型中,两边的平方和等于斜边的平方

3.初始化和清理的概念(了解)

1.当对象产生时,必须初始化成员变量,当对象销毁前,必须清理对象

2.初始化用构造函数,清理用析构函数,这两个函数是编译器调用

4.构造函数和析构函数(重点)

1.初始化的作用和析构函数的作用

// 构造函数的作用
class Maker
{
public:
	// 构造函数的作用是初始化成员变量,是编译器去调用的
	Maker()
	{
		a = 10;
		cout << "构造函数" << endl;
	}

	// 析构函数,在对象销毁前,编译器调用析构函数
	~Maker()
	{
		cout << "析构函数" << endl;
	}
public:
	int a;
};

void test01()
{
	// 实例化对象,内部做了两件事
	// 1.分配空间,2.调用构造函数进行初始化
	Maker m;
	int b = m.a;
	cout << b << endl;

}

// 析构函数的作用
class Maker2
{
public:
	// 有参构造
	Maker2(const char *name,int age)
	{
		cout << "有参构造" << endl;
		//从堆区空间申请
		pName = (char*)malloc(strlen(name) + 1);
		strcpy(pName, name);
		mAge = age;
	}

	void printMaker2()
	{
		cout << "name:" << pName << " age:" << mAge << endl;
	}
	~Maker2()
	{
		cout << "析构函数" << endl;
		// 释放堆区空间
		if (pName != NULL)
		{
			free(pName);
			pName = NULL;
		}
	}
private:
	char *pName;
	int mAge;
};

void test02()
{
	Maker2 m2("翠花",18);
	m2.printMaker2();

}

2.构造函数点和析构函数的注意

  1. 构造函数和析构函数的权限必须是公有的

  2. 构造函数可以重载

  3. 构造函数没有返回值不能用void,构造函数可以有参数

  4. 析构函数没有返回值不能用void没有参数

  5. 有对象产生必然会调用构造函数有对象销毁必然会调用析构函数

  6. 多少个对象产生就会调用多少次构造函数,有多少个对象销毁就会调用多少次析构函数

3.默认的构造函数和默认的析构函数

class Maker
{
public:
	Maker()//默认的构造函数,函数体是空的
	{

	}
	~Maker()//默认的析构函数,函数体也是空
	{

	}
	//编译器默认提供默认的构造函数和析构函数
	void printfMaker()
	{
		a = 100;
		cout << "a=" << a << endl;
	}
private:
	int a;
};

4.拷贝构造函数

1.什么是拷贝构造

class Maker
{
public:
	Maker()
	{
		cout << "无参构造函数" << endl;
		a = 20;
	}
	//拷贝构造函数
	Maker(const Maker &m)
	{
		cout << "拷贝构造函数" << endl;
		a = m.a;
		
	}
	//打印函数
	void printMaker()
	{
		cout << "a=" << a << endl;
	}
private:
	int a;
};
void test01()
{
	Maker m1;
	m1.printMaker();

	// 用一个已有的对象去初始化另一个对象
	Maker m2(m1);
	m2.printMaker();
}

2.编译器提供了默认的拷贝构造函数

class Maker2
{
public:
	Maker2()
	{
		cout << "无参构造函数" << endl;
		a = 20;
	}
	//编译器提供了默认的拷贝构造函数
	//Maker2(const Maker2 &m)
	//{
	//	//默认拷贝构造函数进行了成员变量的简单拷贝
	//	a = m.a;
	//}

	//打印函数
	void printMaker()
	{
		cout << "a=" << a << endl;
	}
private:
	int a;
};


void test02()
{
	Maker2 m1;
	m1.printMaker();
	Maker2 m2(m1);
	m2.printMaker();
}

3.拷贝构造函数中形参要用引用

class Maker3
{
public:
	Maker3(int Ma)
	{
		cout << "有参构造函数" << endl;
		ma = Ma;
	}
	Maker3(const Maker3 &m)
	{
		cout << "拷贝构造函数" << endl;
	}
private:
	int ma;
};

void test03()
{
	Maker3 m1(10);//调用有参构造

	Maker3 m2(m1);

	//如果拷贝构造函数中的形参不是引用
	/*
	Maker3(const Maker3 m)//const Maker3 m=m1;   const Maker3 m(m1);
	{
		cout << "拷贝构造函数" << endl;
	}

	1.Maker3 m2(m1);
	2.const Maker3 m=m1;
	3.const Maker3 m(m1);
	4.const Maker3 m=m1;
	5.进入死循环
	*/
}

5.构造函数的分类及调用(重点)

构造函数的分类

无参构造函数,有参构造函数,拷贝构造函数

类默认提供了哪些函数

默认的构造函数,默认的析构函数,默认的拷贝构造函数,默认的赋值函数

构造函数的调用

void test01()
{
	Maker m;//调用无参构造函数
	Maker m1(10);//调用有参构造
	Maker m2(m1);//调用拷贝构造

	//不常用
	Maker m4 = Maker(10);//调用的是有参构造函数
	Maker m3 = m2;//调用拷贝构造
	cout << "=====" << endl;
	Maker m5 = 10;//Maker m5=Maker(10);
	cout << "=======" << endl;

	Maker m6;
	m6 = m5;//赋值操作

}

6.匿名对象(了解)

匿名对象的生命周期在当前行

void test01()
{
	Maker();//匿名对象的生命周期在当前行
	Maker(10);
	

	//注意,如果匿名对象有名字来接,那么就不是匿名对象

	Maker m1 = Maker();

	cout << "test01()函数结束" << endl;
}

7.拷贝构造函数调用的时机(重点)

1.对象以值方式给函数参数

class Maker
{
public:
	Maker()
	{
		cout << "无参构造函数" << endl;
	}
	Maker(int a)
	{
		cout << "有参构造函数" << endl;
	}
	Maker(const Maker &maker)
	{
		cout << "拷贝构造函数" << endl;
	}
	~Maker()
	{
		cout << "析构函数" << endl;
	}
};
//1.对象以值方式给函数参数
void func(Maker m)//Maker m=m1;
{

}

void test01()
{
	Maker m1;
	func(m1);
}

2.用一个已有的对象去初始化另一个对象

void test02()
{
	Maker m1;
	Maker m2(m1);
}

3.函数的局部对象以值的方式从函数返回

vs Debug(调试)模式下,会调用拷贝构造;
vs Release(发行)模式下不会调用拷贝构造,qt也不调用;

Maker func2()
{
	//局部对象
	Maker m;
	cout << "局部对象的地址:" << &m << endl;

	return m;
}

void test03()
{
	
	Maker m1 = func2();

	cout << "m1对象的地址:" << &m1 << endl;
}

8.构造函数的调用规则(重点难点)

1.如果程序员提供了有参构造,那么编译器不会提供默认构造函数,但是会提供默认的拷贝构造

void test01()
{
	//Maker m;//err

	//Maker m(10);//调用有参构造
	//Maker m2(m);//调用默认的拷贝构造
}

2.如果程序员提供了拷贝构造函数,那么编译器不会提供默认的构造函数和默认的拷贝构造函数

void test02()
{
	//Maker m;
}

9.多个对象的构造和析构(重点难点)

1.如果类有成员对象,那么先调用成员对象的构造函数,再调用本身的构造函数,析构函数的调用顺序反之

2.成员对象的构造函数调用和定义顺序一样

3.注意,如果有成员对象,那么实例化对象时,必须保证成员对象的构造和析构能被调用

class BMW
{
public:
	BMW()
	{
		cout << "BMW构造" << endl;
	}

	~BMW()
	{
		cout << "BMW析构" << endl;
	}
};

class Buick
{
public:
	Buick()
	{
		cout << "Buick构造" << endl;
	}

	~Buick()
	{
		cout << "Buick析构" << endl;
	}
};

class Maker
{
public:
	Maker()
	{
		cout << "Maker构造" << endl;
	}

	~Maker()
	{
		cout << "Maker析构" << endl;
	}
private:
	
	Buick bui;//成员对象
	BMW bmw;//成员对象
};

void test01()
{
	Maker m;
}

4.初始化列表

1.初始化列表是干什么用的

指定调用成员对象的某个构造函数

2.初始化列表只能写在构造函数

3.如果使用了初始化列表,那么所有的构造函数都要写初始化列表

4.如果有多个对象需要指定调用某个构造函数,用逗号隔开

5.可以使用对象的构造函数传递数值给成员对象的变量

class BMW2
{
public:

	BMW2(int a)
	{
		cout << "BMW2有参构造" << a << endl;
	}

	~BMW2()
	{
		cout << "BMW2析构" << endl;
	}
};

class Buick2
{
public:
	Buick2(int b,int c)
	{
		cout << "Buick2构造" << endl;
	}

	~Buick2()
	{
		cout << "Buick2析构" << endl;
	}
};

class Maker2
{
public:
	//初始化列表
	//注意1:初始化列表只能写在构造函数
	/*Maker2() :bmw(10)
	{
		cout << "Maker2构造" << endl;
	}*/
	//如果有多个对象需要指定调用某个构造函数,用逗号隔开
	Maker2(int a,int b,int c) :bmw(a), bui(b,c)
	{
		cout << "Maker2构造" << endl;
	}
	//注意2:如果使用了初始化列表,那么所有的构造函数都要写初始化列表
	Maker2(const Maker &m2) :bmw(40), bui(10,20)
	{

	}
	/*void printMaker2() : bmw(10)
	{

	}*/

	~Maker2()
	{
		cout << "Maker2析构" << endl;
	}
private:
	Buick2 bui;//成员对象
	BMW2 bmw;//成员对象
};

//初始化列表是调用成员对象的指定构造函数
void test02()
{
	Maker2 m(30,10,20);
}

10.对象的深浅拷贝(重点难点)

1.默认的拷贝构造函数进行了简单的赋值操作(浅拷贝)

2.浅拷贝的问题

同一块空间被释放两次

class Student
{
public:
	Student(const char *name, int Age)
	{
		pName = (char*)malloc(strlen(name) + 1);
		strcpy(pName, name);
		age = Age;
	}

	~Student()
	{
		cout << "析构函数" <<endl;
		if (pName != NULL)
		{
			free(pName);
			pName = NULL;
		}
	}
public:
	char *pName;
	int age;
};

void test02()
{
	Student s1("小花", 18);
	Student s2(s1);

	cout << "s1 Name=" << s1.pName << " s1 age=" << s1.age << endl;
	cout << "s2 Name=" << s2.pName << " s2 age=" << s2.age << endl;
}

3.深拷贝解决浅拷贝问题

自己写拷贝构造函数

	//深拷贝
	Student(const Student &stu)
	{
		cout << "自己的拷贝构造函数" << endl;
		//1.申请空间
		pName = (char*)malloc(strlen(stu.pName) + 1);
		//2.拷贝数据
		strcpy(pName, stu.pName);
		age = stu.age;
	}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: C++面向对象编程中,构造函数函数是两个非常重要的概念。 构造函数是一种特殊的函数,它在对象被创建时自动调用,用于初始化对象的数据成员。构造函数的名称与类名相同,没有返回值类型,可以有参数,可以有多个构造函数,以便在创建对象时进行不同的初始化操作。 函数是一种特殊的函数,它在对象被销毁时自动调用,用于清理对象的资源。函数的名称与类名相同,前面加上一个波浪号(~),没有返回值类型,不接受任何参数。 构造函数函数是C++面向对象编程中的两个重要概念,它们的作用是初始化对象和清理对象的资源,是面向对象编程的基础。 ### 回答2: 面向对象是一种程序设计的方法,它以对象为中心,通过封装、继承和多态等机制来组织和管理代码,使程序更加可靠、可重用和易于维护。其中,构造函数函数面向对象程序设计中的重要概念。 构造函数是一种特殊的成员函数,它在对象创建时自动被调用,用于对对象进行初始化。构造函数的名称与类名相同,没有返回值,可以重载,可以带参数,也可以不带参数。构造函数的作用是保证对象在创建时始终处于一种可靠的状态,从而避免程序运行时的错误和异常。 函数是与构造函数相对应的一种成员函数,它在对象销毁时自动被调用,用于对对象进行善后处理。函数的名称与类名相同,前面加上一个波浪号(~),没有参数,也没有返回值。函数的作用是释放对象所占用的资源,例如动态分配的内存、打开的文件、建立的连接等,在对象销毁之前要确保这些资源已经被回收,从而避免内存泄漏和资源浪费。 构造函数函数面向对象程序设计中的重要组成部分,它们体现了对象的生命周期和和管理方式,尤其是在涉及到动态内存分配和释放时更为重要。正确使用构造函数函数可以提高程序的可靠性、可重用性和可维护性,从而更好地实现程序模块化和复用。因此,在面向对象程序设计中,构造函数函数应该被视为重要的设计关注点,特别是在涉及到大型程序或长期运行的系统时。 ### 回答3: 面向对象编程是一种广泛使用的编程范式,它关注的是对象的行为和属性,而不是函数和逻辑。构造函数函数面向对象编程中的两个重要概念,在类的实例化和释放过程中起到了关键的作用。 构造函数是一个类的特殊函数,它习惯性地与类名相同,用于初始化类的实例。构造函数可以接收参数,这些参数可以用来初始化类的成员变量。每当一个新的对象被创建时,构造函数会自动调用,以确保对象被正确地初始化。如果类没有定义构造函数,编译器将提供一个默认构造函数函数是一个类的另一个重要函数,它也习惯性地与类名相同,用于释放由该类创建的资源。函数通常用于释放内存、关闭打开的文件、关闭网络连接等等,以防止资源泄漏和造成程序崩溃。当一个对象被删除或销毁时,函数会自动调用,以确保类能够正确地清理资源。 需要注意的是,当一个对象被复制时,也会调用构造函数函数。使用深拷贝和浅拷贝来管理类的复制,以确保不会复制对象的私有数据。此外,有一些 C++ 特殊语法,如移动语义和智能指针等等,可以用于提高构造函数函数的效率和安全性。 总之,构造函数函数面向对象编程中不可或缺的两个概念。它们可以保证类的正确初始化和释放,从而防止资源泄漏和程序崩溃。编写好构造函数函数是编写高质量 C++ 代码的关键。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ctrl+Alt+L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值