栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++小知识点(六)------C++ primer plus中文版(第六版)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++小知识点(六)------C++ primer plus中文版(第六版)

1、类和动态内存分配 1.1、静态成员初始化

在知识点(四)中的3.2使用static修饰变量,成为静态成员变量,使得所有对象共享变量,但值得注意的是变量类型不仅为static,还是const类型,此时可以在类中声明并初始化,但当没有const修饰时,不可在类声明中初始化,因为初始化是方法文件,而不是头文件

静态成员变量初始化方法:
头文件中
class Student
{
private:
	char *m_name;
	int len;
	static int m_num;
public:
	Student();
	Student(const char *s);
	~Student();
	friend std::ostream & operator<<(std::ostream &os,const Student &stu);
};

cpp文件中
int Student::m_num = 0;			使用作用域解析运算法,但是不包含static
1.2、类的动态内存分配

上面的学生类中有一个char指针用来存储学生的姓名,若采用固定长度的数据会造成资源浪费,此时可以在构造函数中动态的分配内存来存储姓名,待该对象消失时,使用析构函数回收该部分内存即可,因此此时析构函数不可省略。

int Student::m_num = 26;			使用作用域解析运算法,但是不包含static

Student::Student()
{
	m_name = new char[4];
	strcpy_s(m_name,4 ,"C++");
	m_num++;
	cout << "default object created!" << endl;
}

Student::Student(const char *s)
{
	len = strlen(s);
	m_name = new char[len + 1];
	strcpy_s(m_name, len + 1, s);
	m_num++;
	cout << m_num << ":"" << m_name << "" object created by Ordinary constructor" << endl;
}

Student::~Student()
{
	cout << """ << m_name << "" object deleted" << endl;
	m_num--;
	delete[]m_name;
}

std::ostream & operator<<(std::ostream &os, const Student &stu)
{
	os << stu.m_name << endl;
	return os;
}
int main()
{
	Student stu;
	Student fhl("xiaofang");
	return 0;
}
1.3、类的动态内存分配常见错误

现象:

1、对象的值传递
2、对象的直接赋值
3、以值方式返回对象(非引用方式)
上述三种操作都会调用默认拷贝构造函数,生成一个拷贝对象,在对拷贝对象析构的时候会直接影响源对象的析构函数(因为析构函数中包含delete,即造成对同一片空间的二次delete)。

void callme(Student stu)			值传递
{
	cout << stu;
}

int main()
{
	Student stu;
	Student fhl("xiaofang");
	callme(fhl);					报错
	Student fhy = stu;				报错
	return 0;
}

解决方法一:自定义拷贝构造函数(复制构造函数)
了解:深拷贝和浅拷贝的区别

1、	拷贝构造函数原型:
Class_name(const Class_name & Type);

2、	何时调用拷贝构造函数:
	对象间的赋值操作:Student fhl(fhy);
	值传递对象:callme(fhl);
	编译器生成临时对象时(值方式返回对象)
	对已有对象的new操作

3、	默认的拷贝构造函数(浅拷贝)
	生成一个拷贝对象,逐个复制每个非静态成员,因此也称为浅拷贝

4、	自定义拷贝构造函数(深拷贝):重新申请内存空间,避免两次delete同一块内存
	复制的是源对象指针指向的数据,而不是单纯的复制指针,此时在析构delete时,会释放不同的内存空间
	class Student
	{
	private:
		char *m_name;
		int len;
		static int m_num;
	public:
		Student();							默认构造函数
		Student(const char *s);				普通构造函数
		Student(const Student &stu);		拷贝构造函数
		~Student();
		friend std::ostream & operator<<(std::ostream &os,const Student &stu);
	};

	Student::Student(const Student &stu)
	{
		len = strlen(stu.m_name);
		m_name = new char[len + 1];
		strcpy_s(m_name, len + 1, stu.m_name);
		m_num++;
		cout << m_num << ":"" << m_name << "" object created by Copy constructor" << endl;
	}

解决方法二:赋值运算符重载:不创建新对象
并不是所有的问题都归咎于复制构造函数,赋值运算符同样需要注意:

Student fhy = stu;	可能是先调用复制构造函数创建临时对象,然后通过默认赋值对成员逐个复制
但是我通过visual studio 2017实测发现,并不会调用

class Student
{
private:
	char *m_name;
	int len;
	static int m_num;
public:
	Student();									//默认构造函数
	Student(const char *s);						//普通构造函数
	Student(const Student &stu);				//拷贝构造函数
	Student & operator=(const Student &stu);	//赋值运算符重载
	~Student();
	friend std::ostream & operator<<(std::ostream &os,const Student &stu);
};

Student & Student::operator=(const Student &stu)
{
	if (this == &stu)		//防止对象的自我复制
		return *this;
	delete[]m_name;			//释放=左边对象原有内存中的数据,不释放的会浪费此块内存,下次new分配的是一块新空间
	len = stu.len;
	m_name = new char[len + 1];
	strcpy_s(m_name, len + 1, stu.m_name);
	cout << "调用赋值构造函数!" << endl;
	return *this;
}

总结:

在知识点(三)3.3中说:一般提供两个构造函数,一个析构函数,但是到现在需要加上一个:

一般提供三个构造函数(默认构造、普通构造、复制构造函数),一个析构函数

2、其他知识点 2.1、静态成员函数

前有静态成员,现有静态成员函数,在成员函数前加上static变成静态成员函数。

class Student
{
private:
	char *m_name;
	int len;
	static int m_num;
public:
	Student();									//默认构造函数
	Student(const char *s);						//普通构造函数
	Student(const Student &stu);				//拷贝构造函数
	Student & operator=(const Student &stu);	//赋值运算符重载
	static int Number() {return m_num;}			//静态成员函数
	~Student();
	friend std::ostream & operator<<(std::ostream &os,const Student &stu);
};

访问方法:
int count = Student::Number();

同静态成员变量一样,不属于某个对象,所有对象共享一个函数,因此只能访问静态成员变量

2.2、返回对象
1、	返回指向const对象的引用,不会调用复制构造函数
2、	返回非const对象的应用:赋值运算符重载(返回的是指向调用对象的引用)
3、	返回局部对象,不要使用引用方式返回,因为函数执行完毕,引用指向的对象将不存在,而直接返回对象会调用复制构造函数

总之
1、如果方法或函数要返回局部对象,则应返回对象,而不是指向对象的引用。在这种情况下,将使用复制构造函数来生成返回的对象。
2、如果方法或函数要返回一个没有公有复制构造函数的类(如ostream类)的对象,它必须返回一个指向这种对象的引用。
3、有些方法和函数〈如重载的赋值运算符)可以返回对象,也可以返回指向对象的引用,在这种情况下,应首选引用,因为其效率更高。
2.3、指向对象的指针

1、首先创建对象数组,使用对象指针指向数组成员,即对象指针
2、使用new为对象分配内存

int main()
{
	Student stu[2] = {
		Student("xiaofang"),
		Student("xiaowu")
	};
	Student *first = &stu[0];							//对象指针
	Student *second = &stu[1];
	Student *third = new Student(stu[1]);				//已有对象的new操作,将调用拷贝构造函数
	cout << *first << *second << *third << endl;		//<<运算符重载
	delete third;
	return 0;
}	
2.4、对象和指针
1、	对象指针的初始化
	Student *first = &stu[0];				//初始化为已有对象
	Student *third = new Student(stu[1]);	//指针初始化并指向创建的新对象

2、	new和构造函数的搭配
	Student *temp = new Student;						//调用默认构造函数
	
	Student *temp = new Student("xiaofang");			//调用普通构造函数
	
	Student *temp = new Student(stu[0]);				//调用拷贝构造函数
2.5、const成员的初始化方法

在调用构造函数时,应该在执行到构造函数体之前,对const成员进行初始化

class Student
{
private:
	char *m_name;
	int len;
	static int m_num;
	const int stu_size;							//表示最多的学生数量
public:
	Student();									//默认构造函数
	Student(const char *s);						//普通构造函数
	Student(const Student &stu);				//拷贝构造函数
	Student & operator=(const Student &stu);	//赋值运算符重载
	static int Number() {return m_num;}			//静态成员函数
	~Student();
	friend std::ostream & operator<<(std::ostream &os,const Student &stu);
};

初始化方法:
Student(int size):stu_size(size)
{
	m_name = new char[4];
	strcpy_s(m_name,4 ,"C++");
	m_num++;
	cout << "default object created!" << endl;
}

2.6、构造函数的成员初始化列表
语法:构造函数():属性1(值1),属性2(值2)... {}
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) {}
	void PrintPerson() {
		cout << "mA:" << m_A << endl;
		cout << "mB:" << m_B << endl;
		cout << "mC:" << m_C << endl;
	}
private:
	int m_A;
	int m_B;
	int m_C;
};

int main()
 {
	Person p(1, 2, 3);
	p.PrintPerson();
	system("pause");
	return 0;
}

使用成员初始化列表的限定

1、只能用于构造函数
2、必须使用这种格式初始化引用的数据成员;(这是因为引用数据类型在创建时就应该被初始化)
3、const数据成员
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/847207.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号