[C ++] vacaciones de invierno - Clases y Objetos

1. C ++ distribución de la memoria se divide en varias zonas, cada una con características?
En C ++, un programa almacenado en la memoria se divide en cinco áreas:
1), el área de pila (Stack): asignado automáticamente liberado por el compilador, los parámetros de la función de almacenamiento, las variables locales, y similares. Operar de manera similar a una estructura de datos de la pila.
2), el área heap (montón): general se liberan asignado por el programador, si el programador no libera al final del programa puede ser recuperado por el sistema operativo. Tenga en cuenta que se trata de una estructura de datos de la pila totalmente diferente, que toca la lista de distribución similar.
3), zona global / estática (estática): variables globales y variables estáticas se almacenan en uno de los programas particionada compilado
4), los literales de área: almacenar cadenas constantes
5), el área de código de programa: almacenar el cuerpo de la función (función miembro de la clase, la función global) código binario

2. Cuando se define una clase, el compilador generará de forma automática que funciona como una clase? ¿Cuáles son las características de cada una de estas funciones?
Para una clase vacía, compilador C ++ genera función de cuatro predeterminado miembro de: constructor predeterminado, destructor, copia (copia) constructor, función de asignación.
1), un constructor por defecto (constructor por defecto):
constructor llama cuando no hay inicializador explícito. Proporciona un argumento parámetro constructor predeterminado se define como todo formado a partir del constructor sin argumentos, o. Si hay inicializador definir una variable de una clase utiliza el constructor predeterminado. Si una clase definida por el usuario no define explícitamente ningún constructor, el compilador generará automáticamente un constructor predeterminado para ese tipo, conocido como constructor sintético (sintetizado constructor por defecto). El constructor de la clase para proporcionar lenguaje C ++ puede automatizar la tarea de inicialización de objetos. Constructores objetos globales y objetos estáticos en la función main () se invoca antes de la ejecución, los objetos estáticos locales constructor se ejecutan cuando el programa primero en ser llamado cuando la instrucción apropiada. Sin embargo, dada la referencia a un objeto externo cuando la declaración no llama al constructor apropiado, porque el objeto externo solamente se hace referencia a objetos declarados en otro lugar, y realmente no creó un objeto.
2), el destructor:
Cuando el programador no crea un destructor de la clase, a continuación, el sistema crea automáticamente un destructor de la clase, forma: ~ A () {}, se crea el destructor para la clase A. Cuando el programa se completa, el sistema llama automáticamente al destructor se crea automáticamente, un objeto es liberado. El destructor predeterminado nuevo operador no puede Eliminar objetos asignados en el elemento de memoria o un objeto libremente. Si miembros de la clase espacio ocupado se asigna dinámicamente en el constructor, hay que personalizar el destructor entonces de manera explícita usando el operador delete para liberar el constructor utiliza la nueva memoria operador asignado, así como la destrucción de variables ordinarias.
3), el constructor de copia:
Si la escritura no es funciones constructor de copia y de asignación de activos, el compilador de "copia bits de" manera función predeterminada generada automáticamente. Si la clase contiene una variable puntero, entonces la función por defecto dos implícitamente mal.
Cadena tiene dos objetos en a, b, por ejemplo, asumir contenido a.m_data para "Hola", el contenido de b.m_data "mundo".
Ahora será asignado a a b, la función de asignación predeterminada de los medios de "copia bit" Ejecución de b.m_data = a.m_data. Esto hará que tres errores:
A, memoria original b.m_data no se libera, causando pérdida de memoria;
b, b.m_data y punto a.m_data a la misma pieza de la memoria, a o b cualquier cambio afectará a la otra parte;
c , cuando se destruye el objeto, M_DATA fue liberado dos veces.
Constructor de copia se denomina:
A Cuando un objeto existente se va a asignar a otro nuevo objeto, se llama al constructor de copia.
b. Cuando argumentos y parámetros son objeto implicado en la unión del parámetro real, los llamadas de constructor de copia.
c. Cuando el valor de retorno es una función del objeto, para completar la llamada devuelve la función, se llama al constructor de copia.
4) función de asignación:
Cada clase tiene sólo una función de asignación. Constructor de copia y la función de asignación es muy confuso, a menudo conduce a la escritura mal, mal uso. Constructor de copia se llama cuando se crea el objeto y la función de valoración sólo puede ser llamado ha sido alrededor de los objetos.

3. ¿Cuál es copia superficial, lo que es copia profunda?
Copia superficial es la adición de un puntero a la memoria ya existente. La copia profunda es la adición de un puntero, y se abrió un nuevo espacio para un puntero a este nuevo espacio abierto. Poco profunda copiar varios objetos apuntando a un espacio de tiempo, un espacio dará lugar a la liberación de otros objetos espaciales utilizados también dado a conocer, será lanzado de nuevo errores.

  1. Implementar una clase de cadena personalizada, para asegurar correctamente la aplicación de la función principal.
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;
}

miembros de datos de inicialización especiales de
datos constantes const miembros citados, un miembro de los miembros de objetos de clase, los miembros estáticos
1. El único miembro constantelista de inicialización del constructorInicializado
2. En referencia a los miembros solamentelista de inicialización del constructorInicializar
3. Los miembros de la clase de objeto sólo en ellista de inicialización del constructorInicializar
4. inicialización miembro estático

Publicado 43 artículos originales · ganado elogios 4 · Vistas 1200

Supongo que te gusta

Origin blog.csdn.net/weixin_42176221/article/details/103829758
Recomendado
Clasificación