C++侯捷面向对象高级编程笔记

P7 三大函数(big three):拷贝构造,拷贝赋值,析构函数

设计一个拥有指针的类String。

(1)拷贝构造函数如果没有显示的写出来,编译器会默认给一个。当我们设计的class带有指针,就不能用默认的拷贝构造函数,需要自己定义拷贝构造函数,拷贝赋值操作符,析构函数。

(2)拷贝构造函数,首先也是一个构造函数,即函数名和类名相同,没有返回值,与普通的构造函数不同的是,实参为本类对象的一个引用。

(3)拷贝赋值函数,是一个对于赋值操作符的重载,实参也是一个类对象的引用。

(4)析构函数,当对象生命周期结束时,调用析构函数。class中如果有指针,多半就要动态分配,析构函数就要把动态分配的内存释放掉。

(5)浅拷贝与深拷贝。 浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化。深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变。在例子中,编译器给我们的默认big three是浅拷贝,我们自己要求的,也就是要自己定义的是深拷贝。

(6)在有指针的类中,为什么一定要定义自己版本的big three呢(不能用编译器默认提供的)?也就是深拷贝和浅拷贝的理解。

(7)可以看一下下面这个例子,清楚讲了a(b)和a=b区别。拷贝构造函数是对象被创建时调用,赋值函数只能被已经存在了的对象调用。 https://www.cnblogs.com/kaituorensheng/p/3245522.html

P8 堆、栈与内存管理

(8)栈和堆。栈是存在于某作用域的一块内存空间,例如当你调用函数,函数本身即会形成一个stack用来放置它所接受的参数,以及返回地址和局部变量。在函数本体内声明的任何变量,其所使用的内存块都取自上述stack。堆是指由操作系统提供的一块全局内存空间,程序可以动态分配从其中获得若干区块。

(9)stack object的生命期,只要离开作用域,其生命就会结束,就会自动(清理)调用析构函数。static对象的生命在作用域结束之后依然存在,直到整个程序结束。

(10)全局对象,在任何作用域之外的对象,生命也是在整个程序结束后才清理。

(11)heap object,是用new出来的内存,其生命在delete才结束,如果没有显式delete就会内存泄漏。

C++侯捷面向对象高级编程笔记_第1张图片

(12)new是先分配内存,再调用构造函数。编译器转换成三步骤。

C++侯捷面向对象高级编程笔记_第2张图片

(13)delete先调用析构函数,再释放内存。编译器转换为两个动作。

C++侯捷面向对象高级编程笔记_第3张图片

(14)因为String类中有指针,当发生内存泄漏的时候,泄露的内存是类内指针指向对象的内存,不是灰色的部分,如果是Complex类,因为其类没有指针,不会有白色框框的额外内存,则不需要delete。所以最好的做法就是只要有new,就delete。不要考虑其是否带指针。

C++侯捷面向对象高级编程笔记_第4张图片

P10 static、类模板、函数模板等

(15)成员函数有一个隐藏的参数this指针 classname *this,指向本对象的地址。

(16)static函数和成员函数区别在于static函数没有this指针,只能处理静态的数据。静态的数据在class的外面要进行定义(初始化),调用static函数两种方式,通过object调用和通过类名class name调用。

(17) 单例设计模式,只能有一个该类的对象,通过静态函数调用。

C++侯捷面向对象高级编程笔记_第5张图片

改进一下,就是把静态变量放到静态函数中,这样没有调用静态函数时,就不会有静态变量,只有调用才创建。

C++侯捷面向对象高级编程笔记_第6张图片

(18)类模板用的时候必须明确指出typename是哪个类型,函数模板不必明确指出,因为编译器会做实参的推导。

P11 组合与继承

(19)类和类之间的关系分为三种:继承、复合、委托。

(20)复合关系(has_a关系,一个类中有另一个类),构造函数由内而外,析构函数由外而内。

C++侯捷面向对象高级编程笔记_第7张图片

(21)委托关系(通过指针的复合,一个类A中有另一个类B的指针,A中要有big three),通过一个Handle类存有另一个实现类的指针,从而将其调用,这样的方法也会经常用到,实现类的变动不会影响Handle类。

C++侯捷面向对象高级编程笔记_第8张图片

(22)继承关系(is_a关系,有三种继承:public继承、private继承、protected继承),构造还是由内而外,析构由外而内。父类的析构函数必须是virtual

C++侯捷面向对象高级编程笔记_第9张图片

P12 虚函数和多态

(23)子类可以调用父类的函数,是因为子类继承了父类函数的调用权,但是数据的话,直接继承父类的数据,会占用子类内存。父类的函数从继承的角度可以分成三种,非虚函数、虚函数、纯虚函数。

C++侯捷面向对象高级编程笔记_第10张图片

(24)当一个类,又有继承关系,又有组合关系,其构造函数是怎么样的?

//test.h
#include 
using namespace std;

class base
{
public:
	base();
	~base();

private:
	int a_base;
};

base::base()
{
	cout << "constructor base" << endl;
}

base::~base()
{
	cout << "destructor base" << endl;
}

class component
{
public:
	component();
	~component();

private:

};

component::component()
{
	cout << "constructor component" << endl;
}

component::~component()
{
	cout << "destructor component" << endl;
}

class real :public base
{
public:
	real();
	~real();
	component c;
private:

};

real::real()
{
	cout << "constructor real" << endl;
}

real::~real()
{
	cout << "destructor real" << endl;


//test.cpp

#include "test_jicheng.h"

void create()
{
	real r;
}

int main()
{
	create();

	system("pause");
	return 0;
}

运行结果如下,可知,构造函数先调用父类->复合类->子类,析构函数是子类->复合类->父类。

C++侯捷面向对象高级编程笔记_第11张图片

 

P15、P16 conversion function(转换函数)

(26)转换函数,函数名为 operator type() ,type为要转换成为的类型,此函数没有返回类型。

C++侯捷面向对象高级编程笔记_第12张图片

(27) non-explicit-one-argument ctor(一个实参的构造函数),explict的意思是明确的,就是抑制单一实参构造函数的隐式转换,只能显示转换,此例中即为抑制double->Fraction,若没有explict就是可以隐式转换

C++侯捷面向对象高级编程笔记_第13张图片

当上述两个方法共存的时候,编译器会报错,因为两个转换都能行得通,会有歧义。

C++侯捷面向对象高级编程笔记_第14张图片

C++侯捷面向对象高级编程笔记_第15张图片

P17、P18 pointer-like class and function-like class

(28)pointer-like class就是一个类模仿指针,经典例子就是智能指针,智能指针里面带有一个普通的指针,里面会有对操作符*和->的重载。迭代器除了要重载*和->,还有++、--、!=等。

(29)function-like class就是一个类模仿函数,里面有对函数调用符()的重载,这种类所创造的对象叫做函数对象。

P28 引用

(30)从内存的角度看对象(值、指针、引用)。声明一个reference一定要一个初值,引用就是一种代表的关系,object和其引用的大小相同,地址也相同,引用大多用在参数传递上。

 P30 vptr和vtbl(虚指针、虚表) 对象模型

(31)只要类里面有一个或以上虚函数,类中就会有一个虚指针。父类有虚函数,子类继承一定会有虚函数。继承不会仅仅继承成员变量,还会继承函数的使用权,这样子类也可以调用父类的函数,但不会占用内存空间。虚指针会指向虚表,虚表中都放有虚函数指针,指向的是虚函数。

C++侯捷面向对象高级编程笔记_第16张图片

n是代表虚表中的第n个虚函数指针,根据这样的结构,可以适合动态绑定。c++编译器看到一个函数调用,会先区分是静态绑定(直接call)还是动态绑定(三个条件:通过指针调用,向上转型(父类指针指向子类对象),调用虚函数),动态绑定也是多态的一种实现。

(32)this指针通过一个对象调用一个函数,对象的地址就是this指针。

(33)const对象调用non-const函数是错误的,其他三种都行。当成员函数的const和non-const版本同时存在,const object只能调用const版本,non-const object只能调用non-const版本。

 

你可能感兴趣的:(C++)