- guard防卫试声明
#ifndef __COMPLEX__ (guard防卫试声明)
#define __COMPLEX__
...
#endif
- inline关键字
1、写到head里面,class内部的小函数可能是inline方式
2、可以在外部写inline关键字
但是到底是不是inline由编译器决定
- 访问级别
可以交互出现public和private
public:供外界使用的函数
private:私有数据,私有函数
构造函数放到私有区域就是单例(singleton)
- 常量(const)成员函数:
double real() const {return re;}
不改变对象的数据内容。
const complex c1(2,1);
count<<c1.real() ;//如果函数末尾不加const,则说明这个函数可能修改数据
- 能传引用传引用
1、函数传递pass by reference(to const)
因为引用类似指针,如果不允许修改引用的值
那么加上const complex&,如果修改则编译出错
2、返回值,返回值能用引用用引用
return by reference
要区分是否可以return 引用
如果为本地变量,在函数结束的时候释放,不能传引用
inline complex&
__doapl(complex* ths,const complex& r)
{
ths->re += r.re;
ths->im += r.im;
return *ths;//这里当然可以取值后返回,因为ths的内存空间本来就是传入的已经存在。
}
inline complex&
complex::operator += (const complex& r)
{
return __doapl(this,r);//这里也可以,因为this指针指向的对象不是函数内部变量。
}
- 构造函数
名字和class一致,没有返回类型,应该使用initializtion list来进行初始化,单冒号
那一行
差别:一个变量数值设定一个是初始化,一个是赋值,使用initializtion list
直接在初始化阶段进行初始化,效率更高,而不是先初始化然后才进行赋值
- 构造函数可以重载(overloading)
实际上编译的时候会带上全部的参数,实际上他们并不一样。
?real@Complex@@QBENXZ
?real@Complex@@QBENABN@Z
- 析构函数
不带指针的类大部分不需要写析构函数
- friend(友元函数)
取得类的私有变量
private:
double re,im;
friend complex& __doapl(complex*,const complex&)
inline complex&
__doapl(compex* ths,const complex& r)
{
ths->re += r.re;
ths->im += r.im;
return *ths;
}
- 相同class的各个object互为friends(友元)
class complex{
...
public
int func(const complex& param)
{return param.re + param.im;}
private:
double re,im
};
{
complex c1(2,1);
complex c2;
c2.func(c1); //c2 竟然访问了c1的私有成员
}
- 操作符实际上就是一种函数。
1、操作符重载(1) this 成员函数
成员函数实际上自带一个this参数
inline complex& //需要返回具体类型,防止连续操作
complex::operator +=(const complex& r)
//相当于,但是不能这么写
//complex::operator +=(this,const complex& r) //左边为this也就是本对象 右边为传入值 这是固定的
{
return __doapl(this,r)
}
inline complex& //速度更快 比value
__doapl(complex* ths,const complex& r )
{
ths->re += r.re;
ths->im += r.im;
return *ths;//返回的是一个对象,传递者
} //不需要知道接受者是以refrence形式接受
complex c1(2,1);
complex c2(5);
c3 += c2 += c1; //连续操作
c2 += c1;
- 操作符重载(2) 非成员函数
inline complex //value
operator + (const complex& x,const complex& y)//加号操作符重载
{//因为复数的加法不一定是复数加复数。比如实数加复数所以不能用成员函数,成员函数是前后顺序固定的
return complex(real(x) + real(y)),
imag(x) + imag(y));//临时本地变量,声明周期到一行结束
}
//注意这里一定不能return reference,要用value。
inline complex//此处可以返回reference
operator + (const complex& x)//正号操作符重载
{
return x;
}
inline complex
operator - (const complex& x)
{
return complex (-real(x),-imag(x));
}
- 特别重载<<(3)
一定不能写成成员函数
ostream& //返回类型为ostream的引用,处理连续输出
operator<<(ostream& os,const complex& x)
//左边不能加const因为要改变os //右边
{
return os<<'(' <<real(x) <<','<<imag(x)<<')';
}
complex c1(2,1);
complex c2(1,1);
count<<c1;
count<<c1<<c2;//先输出c1修改os,然后返回os给c2,c2输出
- stack:是存在于某个域的一块内存空间 memory space,函数本生形成一个stack用来存放他有接收的参数,已经返回地址。在函数本体内声明的任何变量,其所使用的内存块都取自上述stack
- heap:或者为system heap,是由操作系统提供的一块内存空间程序可以动态的分配
- stack object的生命期
class Complex{...};
...
{
Complex c1(1,2);
}
c1是所谓 stack object,其生命的作用域在结束之际结束
又叫auto object,自动结束的时候调用析构函数。
- static变量
class Complex{...};
...
{
static Complex c2(1,2);
}
c2就是staic object,其声明在作用域结束之后存在,直到整个程序结束。
- global object
class Complex{...}
Complex c(1,2);
int main()
{
...
}
c3是global object,其声明周期在程序结束之后才结束。结束的时候调用析构函数。
class Complex{...};
...
{
Complex* p = new Complex;
...
delete p;
}
class Complex{...};
...
{
Complex *p = new Complex;//没有delete内存泄漏
}
- new操作先分配内存,再调用构造函数
Complex* pc = new Complex(1,2);
编译器转换为
Complex *pc;
void* mem = operator new(sizeof(Complex));//分配内存。调用的就是malloc
pc = static_cast<Complex*>(mem);//转型
pc->Complex::Complex(1,2);//构造函数
//Complex::Complex(pc,1,2) pc就是this指针
- delete先调用析构函数,再释放内存
String* ps = new String("Hello");
...
delete ps;
编译器转换为
String::~String(ps); //调用析构函数,析构函数需要负责动态分配的内存
operator delete(ps); //释放内存,内部为free(ps)
- array new and delete
char* test = new char[3] //array new
delete[] test //array delete 必须搭配使用,否则内存泄漏
//如果delete test那么只唤醒一次析构函数,delete[]唤醒3次
//析构函数
网友评论