[C ++] Winter Vacation - Classes and Objects

1. C ++ memory layout is divided into several zones, each with characteristics?
In C ++, a program stored in the memory is divided into five areas:
1), the stack area (Stack): assigned automatically released by the compiler, the storage function parameters, local variables, and the like. Operate similarly to a stack data structure.
2), the heap area (heap): generally released assigned by the programmer, if the programmer does not release at the end of the program may be recovered by the OS. Note that it is a stack data structure totally different, it touches similar distribution list.
3), global / static zone (static): global variables and static variables are stored in one of the partitioned program compiled
4), literals area: storing constant strings
5), the program code area: storing the function body (class member function, global function) binary code

2. When you define a class, the compiler will automatically generate which functions as a class? What are the characteristics of each of these functions?
For an empty class, C ++ compiler generates four default member function: default constructor, destructor, copy (copy) constructor, assignment function.
1), a default constructor (default constructor):
constructor calls when no explicit initializer. It provides a default parameter argument constructor is defined as all formed from the constructor with no arguments, or. If no initializer define a variable of a class uses the default constructor. If a user-defined class does not explicitly define any constructors, the compiler will automatically generate a default constructor for that type, known as synthetic constructor (synthesized default constructor). The constructor for the class to provide C ++ language can automate the initialization task object. Constructors global objects and static objects in the main () function is invoked before the execution, the constructor local static objects are executed when the program first to be called when the appropriate statement. However, given the reference to an external object when the statement does not call the appropriate constructor, because the external object is only referenced objects elsewhere declared, and did not really create an object.
2), the destructor:
When the programmer does not create a class destructor, then the system automatically creates a class destructor, form: ~ A () {}, the destructor for the class is created A. When the program completes, the system automatically calls the destructor is automatically created, an object is released. The default destructor new operator can not delete objects allocated in memory or object member freely. If class members occupied space is dynamically allocated in the constructor, we must customize the destructor then explicitly using the delete operator to release the constructor uses the new operator allocated memory, just as ordinary variables destruction.
3), the copy constructor:
If the write is not active copy constructor and assignment functions, the compiler will "copy bits" manner automatically generated default function. If the class contains a pointer variable, then the two default function implicitly wrong.
String has two objects in a, b for example, assume a.m_data content for "hello", the contents of b.m_data "world".
It will now be assigned to a b, default assignment function of the "copy bit" means executing b.m_data = a.m_data. This will cause three errors:
A, b.m_data original memory is not released, causing memory leakage;
b, b.m_data and a.m_data point to the same piece of memory, a or b any changes will affect the other party;
c , when the object is destructed, M_DATA was released twice.
Copy constructor gets called:
A When an existing object is to be assigned to another new object, it calls the copy constructor.
b. When arguments and parameters are object involved in binding the real parameter, the copy constructor calls.
c. When the return value is a function of the object, to complete the function call returns, it calls the copy constructor.
4) assignment function:
Each class has only one assignment function. Copy constructor and assignment function is very confusing, often leads to wrong writing, wrong use. Copy constructor is called when the object is created, and the valuation function can only be called has been around objects.

3. What is shallow copy, what is deep copy?
Shallow copy is the addition of a pointer to the already existing memory. The deep copy is the addition of a pointer, and opened up a new space for a pointer to this new space opened up. Shallow copy multiple objects pointing to a space of time, a space will lead to the release of other space objects used also been released, will be released again errors.

  1. Implement a custom String class, to ensure the implementation of the main function correctly.
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;
}

Special initialization data members of
constant data members const, quoted a member of the class object members, static members
1. The only constant memberConstructor initializer listInitialized
2. In reference to members onlyConstructor initializer listInitialize
3. The members of the class object only in theConstructor initializer listInitialize
4. static member initialization

Published 43 original articles · won praise 4 · Views 1200

Guess you like

Origin blog.csdn.net/weixin_42176221/article/details/103829758