C++:复习笔记1

81 阅读3分钟

  • 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(友元函数) 取得类的私有变量

privatedouble 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//析构函数