[C ++] Vacances d'hiver - Classes et objets

1. la mise en mémoire C ++ est divisée en plusieurs zones, chacune ayant des caractéristiques?
En C ++, un programme stocké dans la mémoire est divisée en cinq zones:
1), la zone de pile (Stack): attribué libéré automatiquement par le compilateur, les paramètres de la fonction de stockage, les variables locales, et analogues. Fonctionnent de manière similaire à une structure de données en pile.
2), la zone du segment de mémoire (tas): généralement edit'e attribué par le programmateur, si le programmateur ne libère pas à la fin du programme peut être récupéré par le système d' exploitation. Notez qu'il est une structure de données de pile totalement différent, elle touche liste de distribution similaire.
3), zone globale / statique (statique): les variables globales et les variables statiques sont stockées dans l' un des programmes partitionné compilé
4), la région de littéraux: stocker des chaînes de constantes
5), la zone de code de programme: stocker le corps de la fonction (fonction de membre de classe, fonction globale) code binaire

2. Lorsque vous définissez une classe, le compilateur génère automatiquement qui fonctionne comme une classe? Quelles sont les caractéristiques de chacune de ces fonctions?
Pour une classe vide, le compilateur C génère quatre fonctions de membre par défaut: constructeur par défaut, destructor, constructeur copie (copie), la fonction d'affectation.
1), un constructeur par défaut (constructeur par défaut):
constructeur appelle lorsqu'aucun initialiseur explicite. Il fournit un constructeur argument de paramètre par défaut est défini comme étant tous formés à partir du constructeur sans argument ou. Si aucune initialiseur définir une variable d'une classe utilise le constructeur par défaut. Si une classe définie par l' utilisateur ne définit pas explicitement les constructeurs, le compilateur génère automatiquement un constructeur par défaut pour ce type, connu en tant que constructeur synthétique (constructeur par défaut synthétisé). Le constructeur de la classe pour fournir la langue de C permet d' automatiser l'objet de tâche d'initialisation. Constructors objets globaux et des objets statiques dans la fonction principale () est appelée avant l'exécution, les objets statiques locaux du constructeur sont exécutées lorsque le premier programme à appeler lorsque l'instruction appropriée. Toutefois, compte tenu de la référence à un objet extérieur lorsque l'instruction ne remet pas le constructeur approprié, parce que l'objet externe est que les objets référencés ailleurs déclarés, et ne crée pas vraiment un objet.
2), le destructor:
Lorsque le programmeur ne crée pas un destructeur de classe, le système crée automatiquement un destructeur de classe, sous forme: ~ A () {}, le destructeur de la classe est créée A. Lorsque le programme est terminé, le système appelle automatiquement le destructor est créé automatiquement, un objet est libéré. Le destructeur par défaut nouvel opérateur ne peut pas les objets de suppression attribués dans l' élément de mémoire ou d'un objet librement. Si les membres de la classe espace occupé est allouée dynamiquement dans le constructeur, il faut personnaliser le destructor puis en utilisant explicitement l'opérateur delete pour libérer le constructeur utilise la nouvelle mémoire allouée de l' opérateur, comme la destruction des variables ordinaires.
3), le constructeur de copie:
Si l'écriture n'est pas constructeur de copie active et les fonctions d' affectation, le compilateur manière « copier les bits » fonction par défaut généré automatiquement. Si la classe contient une variable de pointeur, alors les deux fonctions par défaut implicitement faux.
Chaîne a deux objets a, b par exemple, supposons que le contenu a.m_data pour « bonjour », le contenu de b.m_data « monde ».
Il sera maintenant affecté à un b, la fonction d'affectation par défaut des moyens « bit de copie » d' exécution b.m_data = a.m_data. Cela entraînera trois erreurs:
A, b.m_data mémoire d' origine n'est pas libéré, ce qui provoque une fuite de mémoire,
b, et le point b.m_data a.m_data à la même partie de la mémoire, a ou b toute modification aura une incidence sur l'autre partie;
c , lorsque l'objet est détruit, M_DATA a été libéré deux fois.
Copie constructeur est appelé:
A Quand un objet existant doit être affecté à un autre nouvel objet, il appelle le constructeur de copie.
b. Lorsque les arguments et les paramètres sont des objets impliqués dans la liaison du paramètre réel, le constructeur appelle la copie.
c. Lorsque la valeur de retour est une fonction de l'objet, pour remplir les fiches d'appel de fonction, il appelle le constructeur de copie.
4) Fonction d'affectation:
Chaque classe a une seule fonction d'affectation. Copie constructeur et la fonction d'affectation est très confuse, souvent mal conduit à l' écriture, une mauvaise utilisation. Copie constructeur est appelée lorsque l'objet est créé, et la fonction d'évaluation ne peut être appelée a été autour des objets.

3. Quelle est copie superficielle, ce qui est profond copie?
Copie superficielle est l'ajout d'un pointeur vers la mémoire déjà existante. La copie en profondeur est l'ajout d'un pointeur, et a ouvert un nouvel espace pour un pointeur vers ce nouvel espace ouvert. Shallow copier plusieurs objets pointant vers un espace de temps, un espace conduira à la libération d'autres objets spatiaux utilisés également été libérés, sortira à nouveau des erreurs.

  1. Mettre en œuvre une classe de chaîne personnalisée, pour assurer la mise en œuvre de la fonction principale correctement.
class String
{
public:
	String();
	String(const char *pstr);
	String(const String & rhs);
	String & operator=(const String & rhs);
	~String();

	void print();

private:
	char * _pstr;
};

int main(void)
{
	String str1;
	str1.print();
	
	String str2 = "Hello,world";
	String str3("wangdao");
	
	str2.print();		
	str3.print();	
	
	String str4 = str3;
	str4.print();
	
	str4 = str2;
	str4.print();
	
	return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include "string.h"
#include <iostream>
//#include "stdio.h"

using std::cout;
using std::endl;

//using std::string;
//倾向于将std::string当成一个内置类型使用

class Point
{
public:
	//当没有定义默认构造函数时,编译器会主动提供一个构造函数的作用就是用来初始化数据成员
	//一旦定义了一个有参构造函数时,编译器就不会再主动提供默认构造函数
	//构造函数在执行时,先执行初始化表达式,再执行构造函数执行体,
	//	如果没有在构造函数的初始化列表中显式地初始化成员,则该成员将在构造函数体之前执行默认初始化。
	Point()
		:_ix(0),_iy(0)/*,_iz(0)//合法*/
	{
		//_iz = 0;//违法
		cout << "Point()//默认构造函数" << endl;
	}
	Point(int x,int y)
		:_ix(x), _iy(y)
	{
		cout << "Point(x,y)//构造函数" << endl;
	}
	//每个成员在初始化列表之中只能出现一次,其初始化的顺序不是由成员变量在初始化列表中的顺序决定的,
	//	而是由成员变量在类中被声明时的顺序决定的。
	Point(int val)
		:_iy(val),
		_ix(_iy)
	{
		cout << "Point()//初始化顺序" << endl;
	}
	//拷贝构造函数
	Point(const Point &rhs)
		:_ix(rhs._ix),
		_iy(rhs._iy)
	{
		cout << "Point(const Point &rhs)//拷贝构造函数" << endl;
	}
	//析构函数:清理工作
	~Point()
	{
		cout << "~Point()//析构函数" << endl;
	}
	//在类中定义的非静态成员函数中都有一个隐含的this指针,它代表的就是当前对象本身,
	//	它作为成员函数的第一个参数,由编译器自动补全。
	//	比如print 函数的完整实现是:
	void print(/*Point * const this*/)												//这里的const又是为什么
	{
		cout << "(" << _ix << "," << _iy << ")" << endl;
		//cout << "(" << this->_ix << "," <<this->_iy << ")" << endl;					//为什么编译不了?
	}
private:
	int _ix;
	int _iy;
	//const int _iz;
};

class Line
{
	//在C++ 的类中,有4种比较特殊的数据成员,他们分别是常量成员、引用成员、
	//类对象成员和静态成员,他们的初始化与普通数据成员有所不同。
public:
	Line(int x1, int y1, int x2, int y2)
		:_pt1(x1, y1),
		_pt2(x2, y2)
	{
		cout<<"Line(int, int, int, int)//类对象成员初始化" << endl;
	}

	void print()
	{
		_pt1.print();
		cout << "---->" << endl;
		_pt2.print();
	}
private:
	Point _pt1;
	Point _pt2;
};

class String
{
public:
	String()//默认构造函数
	{
		_pstr=new char[10]();
		strcpy(_pstr, "null");
		cout << "默认构造函数" << endl;
	}
	String(const char *pstr)//构造函数
		:_pstr ( new char[strlen(pstr) + 1]())
	{
		strcpy(_pstr, pstr);
		cout << "构造函数" << endl;
	}
	String(const String & rhs)//拷贝构造函数
		:_pstr(new char[strlen(rhs._pstr) + 1]())
	{
		strcpy(_pstr, rhs._pstr);
		cout << "拷贝构造函数" << endl;
	}
	String & operator=(const String & rhs)//赋值运算符函数
	{
		if (this != &rhs)//排除自复制
		{
			//回收原来的堆空间
			delete[] _pstr;

			_pstr = new char[strlen(rhs._pstr) + 1]();
			strcpy(_pstr, rhs._pstr);//深拷贝
		}
		cout << "赋值运算符函数" << endl;
		return *this;
	}
	~String()//析构函数
	{
		delete[] _pstr;
		cout << "析构函数" << endl;
	}

	void print()
	{
		cout << "str:" << _pstr << endl;
	}

private:
	char * _pstr;
};

class Computer
{
public:
	//这种只拷贝指针的地址的方式,我们称为浅拷贝。当两个对象被销毁时,就会造成double free 的问题。
	Computer(char * brand, double price)							
		:_brand(brand),			//浅拷贝
		_price(price)
	{
		cout << "Computer()//构造函数 浅拷贝" << endl;
	}
	Computer(const char * brand, double price)							//这里为什么要用const?
		:_brand ( new char[strlen(brand) + 1]()),	//深拷贝
		_price(price)
	{
		strcpy(_brand, brand);	
		setTotalPrice();
		cout << "Computer()//构造函数 深拷贝" << endl;
	}
	//系统自动提供一个拷贝构造函数, 固定写法
	//1. 引用符号不能去掉,如果去掉,根据拷贝构造函数的调用时机来看,会导致无穷递归,直到栈溢出,程序崩溃
	//2. const关键字不能去掉,如果去掉,当传递过来的是右值时,就无法正确调用拷贝构造函数
	Computer(const Computer &rhs)										
		:_price(rhs._price),
		 _brand(new char[strlen(rhs._brand) + 1]())
	{
		strcpy(_brand, rhs._brand);
		cout << "Computer(const Computer &rhs)//拷贝构造函数" << endl;
		setTotalPrice();
	}
	Computer & operator=(const Computer &rhs)
	{
		//1.避免自复制
		if (this != &rhs)
		{
			//2.回收原来的堆空间
			delete[] _brand;
			//3.深拷贝
			_brand = new char[strlen(rhs._brand) + 1]();
			strcpy(_brand, rhs._brand);
			cout << "Computer & operator=(const Computer &rhs)//赋值运算符函数" << endl;
		}
		setTotalPrice();
	}

	void setTotalPrice()
	{
		_totalPrice += _price;
	}

	//由于数据成员_brand指向了堆空间的区域,所以必须要显式提供一个析构函数进行回收
	//析构函数要清理的是对象的数据成员申请的资源,而对象本身所占据的空间,不是由析构函数来回收的
	//只要对象被销毁,就会自动调用析构函数
	//不建议显示调用析构函数
	//只有delete表达式才能回收对象占据的空间
	~Computer()
	{
		delete[] _brand;
		cout << "~Computer()" << endl;
	}

	void print()
	{
		cout << "The brand is:" << _brand <<"."<< endl;
		cout << "The price is:" << _price << "." << endl;
		cout << "The totalprice is:" << _totalPrice << "." << endl;
	}
private:
	char *_brand;
	double _price;
	//C++ 允许使用static (静态存储)修饰数据成员,这样的成员在编译时就被创建并
	//	初始化的(与之相比,对象是在运行时被创建的),且其实例只有一个,被所有该
	//	类的对象共享,就像住在同一宿舍里的同学共享一个房间号一样。静态数据成员和
	//	之前介绍的静态变量一样,当程序执行时,该成员已经存在,一直到程序结束,任
	//	何该类对象都可对其进行访问,静态数据成员存储在全局 / 静态区,并不占据对象的
	//	存储空间。
	//一般来说,我们不能在类的内部初始化静态数据成员,必须在类的外部定义和初始化静态数据成员,
	//且不再包含static 关键字,
	static double _totalPrice;
};
//初始化静态数据成员
//类型 类名::变量名 = 初始化表达式; //普通变量
//类型 类名::对象名(构造参数); //对象变量
double Computer::_totalPrice = 0;

int testPoint(void)
{
	Point a;
	a.print();

	Point b(1, 2);
	b.print();

	Point c(3);
	c.print();

	Point d = b;
	d.print();

	return 0;
}

int testLine(void)
{
	Line line(1, 2, 3, 4);
	line.print();

	return 0;
}

int testString(void)
{
	String str1;
	str1.print();

	String str2 = "Hello,world";
	str2.print();

	String str3("wangdao");
	str3.print();

	String str4 = str3;		//拷贝构造函数
	str4.print();

	str4 = str2;				//赋值运算符函数
	str4.print();

	//system("pause");
	return 0;
}

int testComputer(void)
{
	//char brand[] = "Alien";
	//Computer com1(brand, 20000);
	//com1.print();
	//strcpy(brand, "change");
	//com1.print();

	//栈对象
	const char brand1[] = "Alien";		
	Computer com2(brand1, 20000);
	com2.print();
	
	//堆对象
	Computer* com3=new Computer("Macbook pro", 20000);
	com3->print();

	//main函数退出之后,静态对象会自动被销毁
	static Computer com4("Xiaomi", 7777);
	com4.print();

	Computer com5 = com4;
	com5.print();

	cout << endl;
	cout << "testComputer() over..." << endl;
	return 0;																	//在这里打断点只有一个析构函数,为什么在return的时候出错误了?
}
//main函数退出之后,全局对象会自动被销毁
//Computer com6("Thinkpad", 8888);

int main(void)
{
	//testPoint();

	//testLine();

	//testString();


	testComputer();
	//cout << endl;
	//cout << "return to main()..." << endl;
	//cout << endl;
	//com6.print();										//退出为什么只有一个析构函数?

	system("pause");
	return 0;
}

membres de données d'initialisation spéciales de
données constantes, les membres const cité un membre des membres de l' objet de classe, membres statiques
1. Le seul membre constantConstructor liste initialiseurInitialisé
2. En ce qui concerne aux membresConstructor liste initialiseurInitialiser
3. Les membres de l'objet de classe que dans laConstructor liste initialiseurInitialiser
4. initialisation de membre statique

Publié 43 articles originaux · louange won 4 · Vues 1200

Je suppose que tu aimes

Origine blog.csdn.net/weixin_42176221/article/details/103829758
conseillé
Classement