cpp 构造与析构(侯捷)

  • inline(内联函数)

    若在函数体内定义完成,变为内联函数的候选人
    inline 函数运行更快,inline 只是建议,具体是否使用由编译器决定

  • 拷贝构造

  • 拷贝赋值

    包含指针需要单独实现,不可用默认的

  • 虚函数

  • 虚函数表

    构造函数

函数重载 :由编译器负责将函数命名唯一化,使用函数名参数 有关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef __COMPLEX__
#define __COMPLEX__
template <typename T>
class complex{
public:
complex(T r=0,T i=0):re(r),im(i){} //inline 使用初始化构造列表,优点构造函数运行更快:因为在变量初始化时就进行了赋值
// (T r=0,T i=0) 默认实参
complex():re(0),im(0){}// 与 上面的构造函数冲突,因此这种构造不允许存在
complex& operator +=(const complex&);
T real() const {return re;} //inline
T imag() const {return im;}//inline

private:
T re,im;
friend complex& __doapl(complex*,const complex&); //友元 可以直接访问类的私有成员
}

#endif

尽量inline由编译器决定

1
2
3
4
5
6
7
8
9
10
inline double imag(const conplex& x){
return x.imag();
}

inline complex&
__doapl (complex* ths,const comlex& r){
ths->re +=r.re;
ths->im +=r.im;
return *ths;
}

友元

同一个class的各个objects互为友元

tips

尽量使用引用传递,入参以及返回值

引用实际上是由编译器使用指针实现

返回值不能使用引用,若返回的值在离开函数后不存在

使用引用的方式传递着,无需知道接受者是以引用的方式接受的

1
2
3
4
5
6
7
8
inline complex&
comolex::operayor += (const comlex& r){
return __doapl(this,r);
}

c2 +=c1;
c2+=c2+=c1;// 因为是引用的方式,所以这种写法是可以的。既传递着无需关心接受者的接收方式

操作符重载

成员函数

1
2
3
complex c1;
complex c2;
c2+=c1;//操作符被作用到左侧的这个类型上
1
2
3
4
5
6
7
8
9
10
11
12

inline complex&
//由于这个函数其他地方可能会用到,因此我们需要把它独立出来
__doapl (complex* ths,const comlex& r){//第二个参数不会改动,因此添加const关键字
ths->re +=r.re;
ths->im +=r.im;
return *ths;
}
inline complex&
comolex::operayor += (const comlex& r){
return __doapl(this,r);
}

非成员函数

临时对象
特殊操作符要使用全局的操作符重载
cout<< conj(c1);
cout<< c1<< conj(c1);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 全局函数
inline compelx
operator +(const compelx&x,const complex&y){
return complex(real(x)+real(y),imag(x)+imag(y));//类型()创建临时变量。
}
inline compelx
operator +(const compelx&x, double y){
complex(real(x)+real(y),imag(x)+y);
}
inline compelx
operator +( double x, const complex&y){
complex(x+real(y),imag(x)+imag(y));
}

inline complex operator +(const complex&x){
return x;
}
inline complex operator -(const complex&x){
return complex(-real(x),-imag(x));
}

operator ==(const comolex& x,const comolex& y){
return real(x)==real(y) &&imag(x)==imag(y);
}
operator ==(const comolex& x,double y){
return real(x)==y &&imag(x)==0;
}
operator ==(double x,const comolex& y){
return x==real(y) &&imag(x)==0;
}
ostream &
operator << (ostream& os,const compelx&x){//os 不能const,因为每次输出改变os的状态
return os<<""<<real(x)<<","<<imag(x)<<")";
}

拷贝构造&赋值构造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class String
{
public:
String(const char* cstr=0);
String(const String& str);
String& operator=(const String& str);
~String();
char* get_c_str() const{return m_data};
private:
char* m_data;
}

inline String::String(const char* cstr=0){
if(cstr){
m_data = new char[strlen(cstr)+1];
strcpy(m_data,cstr);
}else{
m_data=new char[1];
*m_data='\0';
}
}

inline
String& String::operator=(const String& str){
//自我赋值检测
if(this == &str){
return *this;
}
delete[] m_data;
m_data = new char[strlen(str.m_data)+1]
strcpy(m_data,str.m_data);
return this;
}

inline String::~String(){
delete[] m_data;
}

虚函数与虚函数表

图示

虚函数图示

静态绑定

  • call 方法

    动态绑定

满足以下条件

  • 指针
  • 向上转型
  • 调用的是虚函数
编译成图示形式
1
(*(p->vptr)[n])(p);
动态绑定的实现原理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CMyDoc:public CDocument{
virtual Serialize(){....}
};

main(){
CMyDoc myDoc;
...
myDoc.OnFileOpen();
}

CDocument::OnFileOpen(){
...
Serialize();
....
}

当我们调用OnFileOpen时,会将this指针传入,调用的Serialize方法,会在虚函数表上进行查找,虚函数表会讲地址重新定位为CMyDoc 所重写的函数地址

举例说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
B b;
A a=(A)b;
//调用的是A的vfunc1();因为不是使用指针使用。
//编译成汇编时后面跟着call 0x8987979 ,为一串固定的地址
a.vfunc1();

//调用的是B的vfunc1()
//1. 使用指针调用
//2. 向上转型
//3. 虚函数
A* pa=new B;
pa->vfunc1()//call dword ptr [edx]

//调用的是B的vfunc1()
pa=&b;
pa->vfunc1()//call dword ptr [edx]

new与delete的重载

全局函数重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//自定义malloc
void myAlloc(size_t size){
return malloc(size);
}
//自定义free
void myFree(void* ptr){
return free(ptr);
}

//自定义new
inline void* operator new(size_t size){
cout <<"call my global new() \n";
return myAlloc(size);
}

//自定义new[]
inline void* operator new[](size_t size){
cout <<"call my global new[]() \n";
return myAlloc(size);
}

//自定义delete
inline void* operator delete(size_t size){
cout <<"call my global delete() \n";
return myFree(size);
}

//自定义delete[]
inline void* operator delete[](size_t size){
cout <<"call my global delete[]() \n";
return myFree(size);
}

类内部函数重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Foo{
public:
void* operator new(size_t);
void operator delete(void*,size_t);//size_t 可选的
void* operator new[](size_t);
void operator delet[](void*,size_t);//size_t 可选的
}

Foo* p = new Foo;
// 变为以下动作
void* mem = operator new(sizeof(Foo));//call Foo 内的重载new
p = static_cast<Foo*>(mem);
p->Foo::Foo();
...

delete p;
// 变为以下动作
p->~Foo();
operator delete(p)//call Foo 内的重载delete

Foo* p = new Foo[N];
// 变为以下动作
void* mem = operator new(sizeof(Foo)*N +4);//call Foo 内的重载new
p = static_cast<Foo*>(mem);
p->Foo::Foo();//N次
...

delete[] p;
// 变为以下动作
p->~Foo();//N 次
operator delete[](p)//call Foo 内的重载delete

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Foo{
public:
int _id;
long _data;
string _str;
public:
Foo():_id(0){
cout<<"default ctor.this="<<this<<" id="<<_id<<" _data"<<_data<<" stirng="<<_str<<endl;
}

Foo(int i):_id(i){
cout<<" ctor.this="<<this<<" id="<<_id<<" _data"<<_data<<" stirng="<<_str<<endl;
}
//virtual
~Foo() {
cout<<"dtor.this="<<this<<" _id="<<_id<<endl;
}

static void* operator new(size_t size);
static void operator delete(void* pdead,size_t size);
static void* operator new[](size_t size);
static void operator delete[](void* pdead,size_t size);
};

void* Foo::operator new(size_t size){
void* p = malloc(size);
cout<<"call my new size="<<size<<endl;
return p;
}

void Foo::operator delete(void* pdead,size_t size){
cout<<"call my delete size="<<size<<endl;
free(pdead);
}

void* Foo::operator new[](size_t size){
void* p = (void*) malloc(size);
cout<<"call my new[] size="<<size<<endl;
return p;
}

void Foo::operator delete[](void* pdead,size_t size){
cout<<"call my[] delete size="<<size<<endl;
free(pdead);
}

//若无成员函数就调用全局函数
Foo *pf = new Foo;
delete pf;

//强制使用globals 方法

Foo *pf = ::new Foo;
::delete pf;
  • clang mac 64 位电脑运行结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    cout<<"sizeof(int)"<<sizeof(int)<<endl;
    cout<<"sizeof(long)"<<sizeof(long)<<endl;
    cout<<"sizeof(string)"<<sizeof(string)<<endl;
    cout<<"sizeof(Foo)"<<sizeof(Foo)<<endl;
    Foo* p = new Foo(7);
    delete p;
    Foo* pArray= new Foo[5];
    delete[] pArray;

    • 析构函数为非虚函数版本

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      sizeof(int)4
      sizeof(long)8
      sizeof(string)24
      sizeof(Foo)40
      call my new size=40
      ctor.this=0x7ff42a405990 id=7 _data0 stirng=
      dtor.this=0x7ff42a405990 _id=7
      call my delete size=40
      call my new[] size=208
      default ctor.this=0x7ff42a4059c8 id=0 _data0 stirng=
      default ctor.this=0x7ff42a4059f0 id=0 _data0 stirng=
      default ctor.this=0x7ff42a405a18 id=0 _data0 stirng=
      default ctor.this=0x7ff42a405a40 id=0 _data0 stirng=
      default ctor.this=0x7ff42a405a68 id=0 _data0 stirng=
      dtor.this=0x7ff42a405a68 _id=0
      dtor.this=0x7ff42a405a40 _id=0
      dtor.this=0x7ff42a405a18 _id=0
      dtor.this=0x7ff42a4059f0 _id=0
      dtor.this=0x7ff42a4059c8 _id=0
      call my[] delete size=208
    • 析构函数为非虚函数版本

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      sizeof(int)4
      sizeof(long)8
      sizeof(string)24
      sizeof(Foo)48
      call my new size=48
      ctor.this=0x7ff9f4c05990 id=7 _data0 stirng=
      dtor.this=0x7ff9f4c05990 _id=7
      call my delete size=48
      call my new[] size=248
      default ctor.this=0x7ff9f4c059c8 id=0 _data0 stirng=
      default ctor.this=0x7ff9f4c059f8 id=0 _data0 stirng=
      default ctor.this=0x7ff9f4c05a28 id=0 _data0 stirng=
      default ctor.this=0x7ff9f4c05a58 id=0 _data0 stirng=
      default ctor.this=0x7ff9f4c05a88 id=0 _data0 stirng=
      dtor.this=0x7ff9f4c05a88 _id=0
      dtor.this=0x7ff9f4c05a58 _id=0
      dtor.this=0x7ff9f4c05a28 _id=0
      dtor.this=0x7ff9f4c059f8 _id=0
      dtor.this=0x7ff9f4c059c8 _id=0
      call my[] delete size=248

      Process finished with exit code 0

new(),delete()

  • new()
    • 可以重载new 但要求new都有不同的参数
    • 而且其中的第一个参数必须是size_t size
  • delete()
    • 可以写出多个delete,但不会被默认调用,只有在默认版本的new 抛出异常时才会被调用

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Foo{
public:
Foo():m_i(0){cout<<"Foo::Foo()"<<endl;}
Foo(int i):m_i(i){cout<<"Foo::Foo(int)"<<endl;throw Bad();}

void* operator new(size_t size){
cout<<"new size_t size"<<endl;
return malloc(size);
}

void* operator new(size_t size,void* start){
cout<<"(size_t size,void* start)"<<endl;
return start;
}

void* operator new (size_t size,long extra){
cout<<"(size_t size,long extra)"<<endl;
return malloc(size+extra);
}

void* operator new(size_t size,long extra,char init){
cout<<"(size_t size,long extra,char init)"<<endl;
return malloc(size+extra);
}

void operator delete(void* ,size_t ){
cout<<"operator delete(void* ,size_t )"<<endl;
}

void operator delete(void* ,void* ){
cout<<"operator delete(void* pdead,size_t size,void* start)"<<endl;
}
void operator delete(void* ,long ){
cout<<"operator delete(void* pdead,size_t size,,long start)"<<endl;
}
void operator delete(void* ,long ,char ){
cout<<"operator delete(void* pdead,size_t size,,long start,char init)"<<endl;
}
private:
int m_i;
};

Foo start;
Foo* p1= new Foo;
Foo* p2 = new(&start)Foo;
Foo* p3 = new(100)Foo;
Foo* p4 = new(100,'a')Foo;
//Foo* p5 = new(100)Foo(1);
Foo* p6 = new(100)Foo(1);
Foo* p7 = new(100,'a')Foo(1);
Foo* p8 = new(&start)Foo(1);
Foo* p5 = new Foo(1);

例子结果

并没有调用对应的析构函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Foo::Foo()
new size_t size
Foo::Foo()
(size_t size,void* start)
Foo::Foo()
(size_t size,long extra)
Foo::Foo()
(size_t size,long extra,char init)
Foo::Foo()
(size_t size,long extra)
Foo::Foo(int)
libc++abi.dylib: terminating with uncaught exception of type Bad
Process finished with exit code 6