关键词: 类的防卫式声明,模版,内联函数,构造函数以及重载,const,pass by reference(有&符号),friend,操作符重载,返回local object的不能return by reference,拷贝构造函数,拷贝赋值函数(with self assignment),栈stack(装作用域内的东西,函数本体内),堆heap(装global东西的,new/delete),stack物体会自动清理,static物品在程序结束后清理,heap物品是在delete之后清理,new是先分配内存,再调用构造。delete事先调用析构,再释放内存。继承要用(non-virtual,virtual,pure-virtual)
防卫式声明
模版
内联函数
构造函数
构造函数重载(冲突例子)
构造函数放到private区(不允许被外界创建对象的时候)
接上:singleton(也是构造函数放到private了)
const什么东西?不改变结果的就可以加上const 不动才可以const
下面这个:最好加上。
參數傳遞:pass by value vs. pass by reference 引用黄色字
上图,尽量都是传引用(&)。(速度很快)
返回值傳遞:return by value vs. return by reference (to const)
也是,尽量return by reference。
friend友元。 朋友可以直接拿private里的东西
相同class的各個objects互為friends (友元)
上图,看起来好像打破了封装,func直接用了c1,但是确实可以,因为friends
操作符重载±(因为操作符也是函数)
上图_doapl为什么? do assignment plus就是+=
傳遞者無需知道接收者是以 reference 形式接收
為了對付client 的三種可能用法,這兒對應開發三個函數
下面這些函數絕不可return by reference,(因为之前的是加到c2头上)
因為,它們返回的必定是個 local object.一定得return by value
简要理解:而这次是 一个返回临时变量local object,断不可return by reference
反相函数开发
但是上图为什么第一个inline它不return by reference呢?所以这就是标准库没做的最优。标准库也不是圣经。
下面这个是看等不等
共轭复数
上图的operator <<就是重载了“<<”
所以cout<<c1<<conj(c1)会重载到cout身上,是global函数 有两个参数os和x
右边必须是复数,而且是引用速度快。传进来不改变加const。
cout是object,而他就是左边的参数os ostream类型这种type
而且不可以给ostream加const,因为每放进去一个东西,os的状态都在改变。
以上。
第一个例子(复数)的总结:
1.正规军写的构造函数:训练精良
构造函数: complex(double r=0,double i=0) :re(r),im(i) {}
2.函数该不该加const?如果这个函数不会改动数据,就要加上const
3.参数传递考虑pass by reference
4.return的时候也要return by reference
5.数据放在private中,函数绝大部分在public。
上面两张图:为什么+=是成员函数,但是单+不是成员函数而是全局函数?
因为单+有可能加的是实数。所以设成全局函数。
并且加完之后的那个东西,是return by value。
上图是操作符重载“<<” 作用在ostream os身上
避免c1<<cout的写法!
拷贝构造函数,拷贝赋值。(类带着指针就要带着)
析构函数 ~String();
三个特殊函数:拷贝构造-拷贝赋值-析构函数
get_c_str()要带着const
构造函数:包括两个情况。
~string析构函数:就是delete,防止内存泄漏。
s1和s2,s3可以自动调用析构函数
class with pointer members必須有copy ctor和copy op=
如果不用拷贝构造和拷贝赋值:就会下图(浅拷贝):
浅拷贝的危害:内存泄露,以及alias了,两个人指向同一个内存。
深拷贝:有拷贝构造和拷贝赋值
上图:第一个string是类名,第二个string是构造,第三个string是返回自己。
就是————拷贝构造。
下图是:拷贝复制函数(有指针不能不写的函数)分三步走:
并且还要加上:检测自我赋值(因为自我赋值的第一步是杀掉自己):
下图是output函数:
Stack,是存在於某作用域 (scope)的一塊內存空間(memory space)。例如當你調用函數,函數本身即會形成一個 stack用來放置它所接收的參數,以及返回地址。下图的c1就是stack object。出了函数就不行。
内存泄漏:作用域结束,内存空间却还不回来,给不了任何人再次使用。
Heap,是指由操作系統提供的一塊global內存空間,程序可動態分配(dynamicallocated)從某中獲得若干區塊(blocks)
動態分配所得的內存塊(memory block), in VC
debug模式的复数:
release模式的复数:
会发现,存两个位的复数,却用了64字节或16字节,因为有cookie(红色的)。
下图:写一个string类,先想想用什么装string,一般是用指针,不用指定多大。
写构造函数
写big three:
拷贝构造(拷贝了他自己的)
拷贝赋值:只要不是local就可以reference(&)
析构函数
再来个char*
然后写构造函数和析构函数 都是内联函数inline:
然后是拷贝构造函数:
- 浅拷贝:简单地复制对象的成员变量,包括指针。如果对象包含指向动态分配内存的指针,浅拷贝会导致多个对象共享相同的内存区域,这可能会导致资源管理上的问题,比如内存泄漏或数据不一致。
- 深拷贝:为每个新对象分配独立的资源。如果对象包含指针,深拷贝会复制指针指向的数据,确保每个对象都有其独立的内存副本。
- 拷贝赋值函数:使用场景:
- 修改已存在的对象:当你需要将一个对象的状态复制到另一个已经存在的对象中时。
- 赋值操作:当使用赋值运算符
=
将一个对象赋值给另一个同名类型的已存在的对象时。 - 对象的自我赋值:当赋值操作可能涉及到自我赋值(即对象赋值给自己)时,拷贝赋值函数需要进行检查以避免错误。
- 先把目的端清空。
- static总结:静态
静态变量就是都认它,静态函数就是没有this指针
例子:singleton 把构造函数以及拷贝构造弄到private中,别人没法创建对象,但是使用静态的a,public的get函数可以获得a。就创造了一个对象。
改进:用mayers singleton 改进后。如果没有人用singleton。他就不存在。这就是节省。
cout总结:函数实现:
类模版:
函数模版:
namespace:
using namespace std;被封锁在一个单元里;
面向对象编程中,“Composition”(组合)是一种设计原则,它指的是通过将一个对象包含在另一个对象中来实现两个对象之间的关联关系。组合是实现代码复用和灵活性的一种方式,它允许一个对象使用或操作另一个对象的功能。
组合与继承(一种"is-a"关系)不同,它是一种"has-a"关系。以下是组合的一些关键特点:
- "Has-a"关系:
- 当一个对象包含另一个对象时,我们说一个对象"拥有"另一个对象。例如,一个
Car
类可能包含一个Engine
类的对象,表示汽车拥有一个引擎。
- 当一个对象包含另一个对象时,我们说一个对象"拥有"另一个对象。例如,一个
- 灵活性:
- 组合提供了更大的灵活性,因为它允许在运行时动态地替换组件。与继承相比,它不会导致类层次结构的紧密耦合。
继承inheritance(is-a):下面是_list_node是派生类,base是基类。public继承。派生类不仅有自己的,还有父类的。
构造要由内而外(从基类开始构造)
析构要由外而内(从派生类开始析构)
上图中,我觉得ID不用子类来定义,所以non-virtual。
如果想让子类重新定义的东西,可以virtual
如果必须让自类重新定义,因为draw的每一个子类都不一样,所以直接纯虚。