[C ++] Inverno temporada - Classes e Objetos

1. layout de memória C ++ é dividido em várias zonas, cada uma com características?
Em C ++, um programa armazenado na memória é dividida em cinco áreas:
1), a área de pilha (Stack): atribuído liberados automaticamente pelo compilador, os parâmetros da função de armazenamento, as variáveis locais, e similares. Operar de forma semelhante a uma estrutura de dados pilha.
2), a área da pilha (pilha): geralmente libertadas atribuído pelo programador, se o programador não liberta no final do programa podem ser recuperados pelo sistema operacional. Note que é uma estrutura de dados pilha totalmente diferente, que toca lista de distribuição similar.
3), zona global / estática (estático): variáveis globais e variáveis estáticas são armazenados em uma do programa compilado particionado
4), literais área: armazenar cadeias constantes
5), a área de código de programa de: armazenar o corpo da função (função de membro da classe, função global) código binário

2. Quando você define uma classe, o compilador irá gerar automaticamente que funciona como uma classe? Quais são as características de cada uma destas funções?
Para uma classe vazia, C ++ compilador gera a função de quatro padrão membro: construtor padrão, destructor, cópia (cópia) construtor, função de atribuição.
1), um construtor padrão (construtor padrão):
construtor chama quando nenhum inicializador explícito. Ele fornece um construtor argumento parâmetro padrão é definido como todos formados a partir do construtor sem argumentos, ou. Se nenhum inicializador definir uma variável de uma classe usa o construtor padrão. Se uma classe definida pelo utilizador não definir explicitamente qualquer construtor, o compilador gera automaticamente um construtor predefinido para esse tipo, conhecido como construtor sintico (construtor padrão sintetizado). O construtor da classe para fornecer a linguagem C ++ pode automatizar o objeto de tarefa de inicialização. Construtores objetos globais e objetos estáticos na função main () é invocado antes da execução, os objetos estáticos locais do construtor são executadas quando o primeiro programa a ser chamado quando a instrução apropriada. No entanto, dada a referência a um objeto externo quando a instrução não chama o construtor apropriado, porque o objeto externo somente é referenciado objetos em outros lugares declarados, e realmente não criar um objeto.
2), o processo de destruição:
Quando o programador não cria um destruidor de classe, em seguida, o sistema cria automaticamente uma classe destructor, forma: ~ A () {}, o processo de destruição para a classe é criada A. Quando o programa estiver concluído, o sistema chama automaticamente o destruidor é criado automaticamente, um objeto é liberado. O novo operador destrutor default não pode objetos de exclusão alocados na memória ou objeto membro livremente. Se os membros da classe espaço ocupado é alocada dinamicamente no construtor, devemos personalizar o destruidor então explicitamente usando o operador delete para liberar o construtor usa a nova memória operador alocado, assim como a destruição variáveis comuns.
3), o construtor de cópia:
Se a gravação não é funções construtor de cópia e de cessão de ativos, o compilador irá "copiar pedaços" função padrão gerado automaticamente maneira. Se a classe contém uma variável ponteiro, em seguida, a função de dois padrão implicitamente errado.
String tem dois objetos em a, b, por exemplo, suponha conteúdo a.m_data para "Olá", o conteúdo do b.m_data "mundo".
Vai agora ser atribuído a um b, função de atribuição padrão dos meios "cópia bit" Executando b.m_data = a.m_data. Isso fará com que três erros:
A, memória original b.m_data não é liberada, causando vazamento de memória;
b, b.m_data e ponto a.m_data para o mesmo pedaço de memória, a ou b quaisquer mudanças afetarão a outra parte;
c , quando o objecto é destruído, m_Data foi libertada duas vezes.
construtor de cópia é chamado:
Uma Quando um objeto existente é para ser atribuído a outro novo objeto, ele chama o construtor de cópia.
b. Quando argumentos e parâmetros são objeto envolvido na ligação do parâmetro real, as chamadas cópia do construtor.
c. Quando o valor de retorno é uma função do objeto, para completar a chamada de função retorna, ele chama o construtor de cópia.
4) função de atribuição:
Cada classe tem apenas uma função de atribuição. Cópia construtor e função de atribuição é muito confuso, muitas vezes leva a escrever errado, uso errado. construtor de cópia é chamado quando o objeto é criado, e a função de avaliação só pode ser chamado tem sido em torno de objetos.

3. O que é cópia superficial, o que é cópia profunda?
Cópia superficial é a adição de um ponteiro para a memória já existente. A cópia profunda é a adição de um ponteiro, e abriu-se um novo espaço para um ponteiro para este novo espaço abriu. Rasa copiar vários objetos que apontam para um espaço de tempo, um espaço levará à liberação de outros objetos espaciais usados também foram liberados, será lançado novamente erros.

  1. Implementar uma classe String personalizado, para garantir a implementação da função principal corretamente.
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;
}

membros de dados de inicialização especiais de
dados constantes membros const, citou um membro dos membros do objeto classe, membros estáticos
1. O único membro constantelista inicializador construtorInicializado
2. Em referência a membros somentelista inicializador construtorInicializar
3. Os membros do objeto de classe somente nolista inicializador construtorInicializar
4. inicialização membro estático

Publicado 43 artigos originais · ganhou elogios 4 · Vistas 1200

Acho que você gosta

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