c++面向对象高级编程

c++面向对象高级编程(上)

 

防卫式声明:

#ifndef_xxxxxxx_

#define_xxxxxxx_

...

#endif

 

 

inline

只是一种建议,编译器并不一定会执行

 

 

 

构造函数

初始化列表的方法设置参数

 

complex (double r=0,double i=0): re (r), im (i){ }----

//拥有更高的效率

 

轻易不要用友元函数,打破了封装

 

 

相同class的各个object互为friends

 

 

-----------------------------------------------------

小结:

  1. 数据尽量在private
  2. 参数尽可能以reference传递
  3. 返回值尽量以reference传递
  4. 类的本体函数应该加const就要加
  5. 构造函数尽量用初始化列表的方法

 

###一种不可以传reference的情况: 函数里面local的东西

eg:一个函数处理a+b ,最后的结果返回到a或b时,可以用reference传递

但是,如何要返回在函数内部运算中创建的c时,则不能使用reference的方式进行传递

因为在函数执行完毕后c的本体会被消解,而依赖于本体的引用也不复存在。

 

操作符重载(有成员函数和非成员函数两种)与临时对象:

 

所有的成员函数一定带着一个隐藏的参数----this(是一个指针

指向这个调用这个函数的对象本身

 

return by reference 语法分析

 

传递者无需之调接受者是以reference形式来接收

 

单纯的+=并不在乎最后返回什么 ,为什么要用complex& ?

想一想如果需要 c3+=c2+=c1;

 

####设计操作符重载时一定要多考虑使用者连续使用的情况(如上例)

 

2.操作符重载-非成员函数的写法

 

为了应付用户三种可能的写法,需要开发三个函数:

c2=c1+c2;

c2=c1+5;

c2=7+c1;

分别对应不同额度操作符重载函数。

 

Q&A:

这三个函数为什么不能 return by reference ?

因为加的结果是在函数里面创建出来的。---在这里是创建了一个temp object

(临时对象)。

 

temp object--

typename( )------ eg: complex( ) 直接类名加参数 不生成具体对象,生命周期在下一行就会结束。

临时对象是一种特殊语法,一般人少用,但标准库用的较多。

 

<<操作符重载的特别之处,不能用成员函数的方式进行重载,因为成员函数的操作符重载必须作用于左边

而左边是cout,而它不能识别这种复数类。

 

解刨cout--

 

注意操作符不能使用const,因为在输入的过程中,他的状态会不断的发生改变。

ex,这里的返回类型可以用void吗,想想为什么。

 

 

BIG Three, 拷贝构造函数,拷贝赋值函数,析构函数--三种特殊函数:

 

析构函数--构造函数中如果有动态分配内存,必须自定义析构函数,

同时析构函数中必须释放分配的内存。

 

 

有指针时,赋值函数一定要设置自己的拷贝赋值函数,避免造成浅拷贝(如上图

此时既有内存泄露,又有两个东西指向同一个东西,十分危险!

 

Q&A:

那么怎么进行深拷贝呢?

0.检测自我赋值(self-assessment) 。 good robust!!!

1.delete自己

2.重新分配一个足够大的内存

3.把内容拷贝过来

 

字符串的output 函数,

直接把指针给ostream即可

 

 

 

 

 

 

堆、栈与内存管理

 

stack: 用于某个作用域的一块内存空间,自动分配,自动释放

heap:又叫 system heap ,是由os提供的一块global的内存空间,程序可

dynamic allocated,从中获得若干blocks

 

四种object的生命周期:

  1. stack object 的生命期 ,作用域结束后就结束
  2. static local object,其生命在作用域结束后仍然存在,知道整个程序结束
  3. global objects , 类似static
  4. heap objects , 其生命周期直到被 deleted才被释放。必须主动结束,不然会导致内存泄露

 

 

new:先分配memory ,再调用ctor

 

delete:先调用dtor,再释放memory

 

动态分配所得到的内存块(memory block),in VC,不同编译器具体情况不同

 

分配的内存必须是16的倍数

顶部和底部是cookie,用来标记的大小(16进制),最后一个位来标记内存是否被使用

如果是1,则被使用,例如 41,40表示64个字节的内存(4*16),1表示被分配,

想想为什么最后一位可以用来表示内存的分配情况?

 

第二图,第四图是非调试模式下的常规概念。

字符串只占用一个指针,所以大小是四个字节,为了满足16的倍数,需要补充4个字节,

把12变为14.

 

动态分配得到的array。

 

 

 

内存泄漏不是泄漏了左边,而是右边的。

 

小结----构建一个类

定义成员变量;

构造函数;

big three:拷贝构造,拷贝赋值,析构(都没有const);

是否需要其余辅助成员函数;

 

进一步 补充 static

 

静态成员变量就是通过this point 来同步需要取得的不用的对象

静态成员函数没有this point ,所以它只能处理静态的成员变量数据

 

静态的数据在类的外部要对其进行定义,并不一定要赋初值。

 

静态函数的调用方式有两种:

1.通过类名直接调用; Account:: set_rate(5.0)

2.通过对象进行调用。a.set_rate(7.0)

 

进一步补充:把ctors放在private区 singleton

改进版:

想想好在哪里。

 

进一步补充:cout

 

 

 

 

组合与继承

 

composition(组合),表示has-a

我里面有一个另一种东西

 

adapter-一种设计模式,封装改造之前的东西,使其功能

 

delegation 委托--compositon by reference

 

有这个指针并不一定代表此刻已经创建了这样一个对象,只是在需要的时候才会创建

并调用。所以叫通过引用进行组合。

piml point to implement

 

copy on write

在上图中,如果a要修改hello 里的内容,编译器并不会让他直接修改,而是先copy一份一样的

然后让他基于这个副本进行修改。

 

Inheritance继承,表示is-a

 

 

构造的时候先父,后他,最后是自己。

 

虚函数与多态

 

虚函数 inheritance with virtual functions

 

no-virtual fun :不希望子类重新定义

virtual fun:希望子类在需要的时候重新定义

pure virtual fun:子类必须重新定义才可以使用

 

template method ,设计模式的一种,父类中有一些方法不知道如何实现,便设计为虚函数,

留待子类去实现。 框架设计中比较常见。

 

delegation+inheritance

Observer的设计模式就是用delegation+inheritance所实现的

 

composite(设计模式) -父类指针指向子类对象

 

prototype

problem:父类不知道子类长什么样,因此不知道如何去创建

solution:子类创建一个静态的自己,交给父类让他能够知道自己

又一个私有的构造函数,并重写一个clone函数,方便父类创建自己

 

Q&A:

Q:为什么还有一个protected的构造函数?

A:因为第一个构造函数构造的时候,因为需要调用addPrototype(),让父类存储这种类型,

而之后clone的时候并不需要,所以需要另一个构造函数,并通过增加一个参数(这个参数并没有用)

的方式来作以区分。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值