对象的构造和析构
1.基本概念
创建一个对象时,常常需要作某些初始化的工作,例如对数据成员赋初值。注意,类的数据成员是不能在声明类时初始化的。
为了解决这个问题,C++编译器提供了构造函数(constructor)来处理对象的初始化。构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。
-
构造函数定义及调用
1)C++中的类可以定义与类名相同的特殊成员函数,这种与类名相同的成员函数叫做构造函数;
2)构造函数在定义时可以有参数;
3)没有任何返回类型的声明。
-
构造函数的调用
自动调用:一般情况下C++编译器会自动调用构造函数
手动调用:在一些情况下则需要手工调用构造函数
-
析构函数定义及调用
1)C++中的类可以定义一个特殊的成员函数清理对象,这个特殊的成员函数叫做析构函数
语法:~ClassName()
2)析构函数没有参数也没有任何返回类型的声明
3)析构函数在对象销毁时自动被调用
4)析构函数调用机制
C++编译器自动调用
-
设计构造函数和析构函数的原因
面向对象的思想是从生活中来,手机、车出厂时,是一样的。生活中存在的对象都是被初始化后才上市的;初始状态是对象普遍存在的一个状态的
-
普通方案:
为每个类都提供一个public的initialize函数;
对象创建后立即调用initialize函数进行初始化。
- 优缺点分析
1)initialize只是一个普通的函数,必须显示的调用
2)一旦由于失误的原因,对象没有初始化,那么结果将是不确定的,没有初始化的对象,其内部成员变量的值是不定的
3)不能完全解决问题
类似于下面的情况更加说明了构造函数的必要性:
#include <iostream>
using namespace std;
class Test3
{
public:
void init(int _a, int _b)
{
a = _a;
b = _b;
}
protected:
private:
int a;
int b;
};
void main31()
{
Test3 t1;
int a = 10;
int b = 20;
t1.init(a, b);
Test3 tArray[3];
tArray[0].init(1, 2);
tArray[1].init(1, 2);
tArray[2].init(1, 2);
Test3 t21; t21.init(1, 2);
Test3 t22; t22.init(1, 2);
Test3 t23; t23.init(1, 2);
Test3 tArray2[3] = {t21, t22, t23};
Test3 tArray3[1999] = {t21, t22, t23};
cout<<"hello..."<<endl;
system("pause");
return ;
}
- 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
基础(有参)构造函数和析构函数示例代码
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Test
{
public:
Test(int a,int flag){
m_a = a;
obj_flag = flag;
ptr = (char*)malloc(100);
if (NULL == ptr)
obj_flag = 0;
strcpy(ptr, "abcdefg");
cout << obj_flag<<"/tI am constructor function" << endl;
}
void print()
{
cout << m_a << endl;
cout << ptr << endl;
cout << obj_flag << endl;
}
~Test()
{
if (ptr != NULL)
{
free(ptr);
ptr = NULL;
}
cout << obj_flag << "/tI am destructor function" << endl;
}
protected:
private:
char *ptr;
int m_a;
int obj_flag;
};
void objplay()
{
Test t1(10,20);
t1.print();
printf("分隔符\n");
Test t2(30,40);
t2.print();
}
int main(void)
{
objplay();
system("pause");
return 0;
}
- 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
- 55
- 56
- 57
- 58
- 59
- 60
- 61
2.构造函数分类及调用规则
2.1.无参数构造函数
调用方法: Test t1, t2;
#include <iostream>
using namespace std;
class Test2
{
public:
Test2()
{
m_a = 0;
m_b = 0;
cout << "无参数构造函数" << endl;
}
public:
void printT()
{
cout << "普通成员函数" << endl;
}
private:
int m_a;
int m_b;
};
void main()
{
Test2 t1;
cout << "hello..." << endl;
system("pause");
return;
}
- 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
2.2.有参数构造函数
一共三种情况调用有参构造函数
- 括号法:
ClassName obj(int a)
2.等号法:ClassName obj=(3,4)
3.显示调用 ClassName obj=ClassName(3,4)
示例代码如下:
#include <iostream>
using namespace std;
class Test2
{
public:
Test2()
{
m_a = 0;
m_b = 0;
cout << "无参数构造函数" << endl;
}
Test2(int a)
{
m_a = a;
m_b = 0;
cout <<m_a<< "/tTest2(int a)有参数构造函数" << endl;
}
Test2(int a, int b)
{
m_a = a;
m_b = b;
cout << "Test2(int a, int b)有参数构造函数" << endl;
}
Test2(const Test2& obj)
{
cout << "copy构造函数 " << endl;
}
public:
void printT()
{
cout << "普通成员函数" << endl;
}
private:
int m_a;
int m_b;
};
void main()
{
Test2 t1(1, 2);
t1.printT();
Test2 t2 = (3, 4, 5, 6, 7);
Test2 t3 = 5;
Test2 t4 = Test2(1, 2);
t1 = t4;
cout << "hello..." << (3, 4, 5, 6, 7)<<endl;
system("pause");
return;
}
- 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
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
2.3.拷贝构造函数
#include <iostream>
using namespace std;
class Test
{
public:
Test()
{
m_a = 0;
cout << "无参数构造函数" << endl;
}
Test(int a)
{
m_a = a;
cout << "有参数构造函数" << endl;
}
Test(const Test & obj)
{
m_a = obj.m_a + 100;
cout << "我也是构造函数 " << endl;
}
void printT()
{
cout << "m_a/t" << m_a << endl;
cout << "普通成员函数" << endl;
}
protected:
private:
int m_a;
};
int main(void)
{
Test t1;
Test t0(2);
cout << "---" << endl;
t0 = t1;
cout << "---" << endl;
Test t2 = t1;
t2.printT();
system("pause");
return 0;
}
- 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
#include <iostream>
using namespace std;
class Test
{
public:
Test()
{
m_a = 0;
cout << "无参数构造函数" << endl;
}
Test(int a)
{
m_a = a;
cout << "有参数构造函数" << endl;
}
Test(const Test & obj)
{
m_a = obj.m_a + 100;
cout << "我也是构造函数 " << endl;
}
void printT()
{
cout << "m_a\t" << m_a << endl;
cout << "普通成员函数" << endl;
}
protected:
private:
int m_a;
};
int main(void)
{
Test t1;
Test t2(t1);
t2.printT();
system("pause");
return 0;
}
- 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
- 函数调用时,实参初始化形参(形参是一个元素不是引用)
#include <iostream>
using namespace std;
class Location
{
public:
Location(int xx = 0, int yy = 0)
{
X = xx; Y = yy; cout << "Constructor Object.\n";
}
Location(const Location & obj)
{
X = obj.X; Y = obj.Y; cout << "我也是构造函数 " << endl;
}
~Location()
{
cout << X << "," << Y << " Object destroyed." << endl;
}
int GetX() { return X; } int GetY() { return Y; }
private: int X, Y;
};
void f(Location p)
{
cout << p.GetX() << endl;
}
void playobj()
{
Location a(1, 2);
Location b = a;
cout << "b对象已经初始化完毕" << endl;
f(b);
}
void main()
{
playobj();
cout << "hello..." << endl;
system("pause");
return;
}
- 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
#include <iostream>
using namespace std;
class Location
{
public:
Location(int xx = 0, int yy = 0)
{
X = xx; Y = yy; cout << "Constructor Object.\n";
}
Location(const Location & obj)
{
X = obj.X; Y = obj.Y; cout << "Copy Constructor Object.\n";
}
~Location()
{
cout << X << "," << Y << " Object destroyed." << endl;
}
int GetX() { return X; } int GetY() { return Y; }
private: int X, Y;
};
Location g()
{
Location A(1, 2);
return A;
}
void objplay2()
{
g();
}
void objplay3()
{
Location m = g();
printf("匿名对象,被扶正,不会析构掉\n");
cout << m.GetX() << endl;;
}
void objplay4()
{
Location m2(1, 2);
m2 = g();
printf("因为用匿名对象=给m2, 匿名对象,被析构\n");
cout << m2.GetX() << endl;;
}
void main()
{
objplay2();
objplay3();
objplay4();
cout << "hello..." << endl;
system("pause");
return;
}
- 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
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 一旦在子函数中·return obj·,就会立即调用拷贝构造函数
- 子函数的返回值是一个匿名对象,只有当把该返回值用来初始化一个同类型的对象时,匿名对象才不会析购
- 没有接收返回值名或者将返回值赋值给一个已经初始化过的对象,匿名对象都将被析构
#include <iostream>
using namespace std;
class Location
{
public:
Location(int xx = 0, int yy = 0)
{
X = xx; Y = yy; cout << "Constructor Object.\n";
}
Location(const Location & obj)
{
X = obj.X; Y = obj.Y; cout << "Copy Constructor Object.\n";
}
Location(const Location & obj1, const Location & obj2)
{
X = obj1.X + obj2.X; Y = obj1.Y + obj2.Y; cout << "Copy Constructor Object.\n";
}
~Location()
{
cout << X << "," << Y << " Object destroyed." << endl;
}
int GetX() { return X; } int GetY() { return Y; }
private: int X, Y;
};
void main()
{
Location test1(1, 2);
Location test2(3, 4);
Location test3(test1, test2);
cout << test3.GetX() << "\t" << test3.GetY() << endl;
cout << "hello..." << endl;
system("pause");
return;
}
- 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
2.4默认构造函数
二个特殊的构造函数
一旦类中定义了任何一个有参构造函数或者拷贝构造函数,却没有显示的定义无参构造函数,编译器都不会提供默认的无参构造函数.所以在使用className obj
这样声明一个对象的时候,如果不调用有参构造函数或者拷贝构造函数会编译失败!
2.5调用规则
1)当类中没有定义任何一个构造函数时,c++编译器会提供默认无参构造函数和默认拷贝构造函数
2)当类中定义了拷贝构造函数时,c++编译器不会提供无参数构造函数
3) 当类中定义了任意的非拷贝构造函数(即:当类中提供了有参构造函数或无参构造函数),c++编译器不会提供默认无参构造函数
4 )默认拷贝构造函数成员变量简单赋值
总结:只要你写了构造函数,那么你必须用。
构造析构阶段性总结:
1)构造函数是C++中用于初始化对象状态的特殊函数
2)构造函数在对象创建时自动被调用
3)构造函数和普通成员函数都遵循重载规则
4)拷贝构造函数是对象正确初始化的重要保证
5)必要的时候,必须手工编写拷贝构造函数
3.深拷贝和浅拷贝
- 默认复制构造函数可以完成对象的数据成员值简单的复制
- 对象的数据资源是由指针指示的堆时,默认复制构造函数仅作指针值复制
- 解决办法是手工实现拷贝构造函数,一旦显示实现拷贝构造函数,编译器不会提供默认的浅拷贝构造函数。
示例代码:
#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
class Test{
public:
Test(const char * ptr)
{
m_len = strlen(ptr);
m_p = (char*)malloc(m_len+1);
strcpy(m_p,ptr);
}
Test(const Test & obj)
{
m_len = obj.m_len;
m_p = (char*)malloc(m_len+1);
strcpy(m_p,obj.m_p);
}
~Test()
{
if(NULL != m_p)
{
free(m_p);
m_len = 0;
m_p = NULL;
}
}
void operator=(Test &obj)
{
if (m_p != NULL)
{
free(m_p);
m_p = NULL;
m_len = 0;
}
cout<<"测试有没有调用我。。。。"<<endl;
m_len = obj.m_len;
m_p = (char*)malloc(m_len+1);
strcpy(m_p,obj.m_p);
}
private:
int m_len;
char *m_p;
protected:
};
void objplaymain()
{
Test obj1("abcdefg");
Test obj2 = obj1;
Test obj3("obj3");
obj3 = obj1;
}
int main()
{
objplaymain();
cout << "Hello World!" << endl;
return 0;
}
- 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
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
4.多个对象构造和析构
-
C++中提供了初始化列表对成员变量进行初始化
语法规则
Constructor::Contructor() : m1(v1), m2(v1,v2), m3(v3)
{
// some other assignment operation
}
-
使用初始化列表出现原因:
1.必须这样做:
如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,如果没有初始化列表,那么他将无法完成第一步,就会报错。
2.类成员中若有const修饰,必须在对象初始化的时候,给const int m 赋值。当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
-
注意概念
- 初始化:被初始化的对象正在创建
- 赋值:被赋值的对象已经存在
注意:
1) 成员变量的初始化顺序与声明的顺序相关,与在初始化列表中的顺序无关
2) 初始化列表先于构造函数的函数体执行
#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
#include <iostream>
using namespace std;
class A
{
public:
A(int _a)
{
a = _a;
cout << "构造函数" << "a" << a << endl;
}
~A()
{
cout << "析构函数" << "a" << a << endl;
}
protected:
private:
int a;
};
class B
{
public:
B(int _b1, int _b2) : a1(1), a2(2), c(0)
{
}
B(int _b1, int _b2, int m, int n) : a1(m), a2(n), c(0)
{
b1 = _b1;
b2 = _b2;
cout <<"B的构造函数"<<endl;
}
~B()
{
cout<<"B的析构函数" <<endl;
}
protected:
private:
int b1;
int b2;
A a2;
A a1;
const int c;
};
void obj10play()
{
B ojbB2(1, 2,3, 4);
return ;
}
int main()
{
obj10play();
system("pause");
return 0;
}
- 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
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
5.调用顺序
1)当类中有成员变量是其它类的对象时,首先调用成员变量的构造函数,调用顺序与声明顺序相同;之后调用自身类的构造函数
2)析构函数的调用顺序与对应的构造函数调用顺序相反
#include "iostream"
using namespace std;
class ABCD
{
public:
ABCD(int a, int b, int c)
{
this->a = a;
this->b = b;
this->c = c;
printf("ABCD() construct, a:%d,b:%d,c:%d \n", this->a, this->b, this->c);
}
~ABCD()
{
printf("~ABCD() construct,a:%d,b:%d,c:%d \n", this->a, this->b, this->c);
}
int getA()
{
return this->a;
}
protected:
private:
int a;
int b;
int c;
};
class MyE
{
public:
MyE():abcd1(1,2,3),abcd2(4,5,6),m(100)
{
cout<<"MyD()"<<endl;
}
~MyE()
{
cout<<"~MyD()"<<endl;
}
MyE(const MyE & obj):abcd1(7,8,9),abcd2(10,11,12),m(100)
{
printf("MyD(const MyD & obj)\n");
}
protected:
public:
ABCD abcd1;
ABCD abcd2;
const int m;
};
int doThing(MyE mye1)
{
printf("doThing() mye1.abc1.a:%d \n", mye1.abcd1.getA());
return 0;
}
int run2()
{
MyE myE;
doThing(myE);
return 0;
}
int run3()
{
printf("run3 start..\n");
ABCD(400, 500, 600);
ABCD abcd = ABCD(100, 200, 300);
printf("run3 end\n");
return 0;
}
int main()
{
run2();
run3();
system("pause");
return 0;
}
- 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
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
容易引发危险,因为只调用构造函数会产生匿名对象。匿名对象不合适处理会被立即析构,所以相当于深一个层次的构造函数调用毫无意义。
示例代码如下:
#include "iostream"
using namespace std;
class MyTest
{
public:
MyTest(int a, int b, int c)
{
this->a = a;
this->b = b;
this->c = c;
}
MyTest(int a, int b)
{
this->a = a;
this->b = b;
MyTest(a, b, 100);
}
~MyTest()
{
printf("MyTest~:%d, %d, %d\n", a, b, c);
}
protected:
private:
int a;
int b;
int c;
public:
int getC() const { return c; }
void setC(int val) { c = val; }
};
int main()
{
MyTest t1(1, 2);
printf("c:%d", t1.getC());
system("pause");
return 0;
}
- 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
6.对象的动态管理
1.new和delete基本语法
1)在软件开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除。在C语言中是利用库函数malloc和free来分配和撤销内存空间的。C++提供了较简便而功能较强的运算符new和delete来取代malloc和free函数。
注意: new和delete是运算符,不是函数,因此执行效率高。
2)虽然为了与C语言兼容,C++仍保留malloc和free函数,但建议用户不用malloc和free函数,而用new和delete运算符。new运算符的例子:
new int;
new int(100);
new char[10];
new int[5][4];
float *p=new float (3.14159);
3)new和delete运算符使用的一般格式为:
用new分配数组空间时不能指定初值。如果由于内存不足等原因而无法正常分配空间,则new会返回一个空指针NULL,用户可以根据该指针的值判断分配空间是否成功。
2.类对象的动态建立和释放
使用类名定义的对象都是静态的,在程序运行过程中,对象所占的空间是不能随时释放的。但有时人们希望在需要用到对象时才建立对象,在不需要用该对象时就撤销它,释放它所占的内存空间以供别的数据使用。这样可提高内存空间的利用率。
C++中,可以用new运算符动态建立对象,用delete运算符撤销对象比如:
Box *pt;
pt=new Box;
如
cout<<pt->height;
cout<<pt->volume( );
C++还允许在执行new时,对新建立的对象进行初始化。如
Box *pt=new Box(12,15,18);
这种写法是把上面两个语句(定义指针变量和用new建立新对象)合并为一个语句,并指定初值。这样更精炼。
新对象中的height,width和length分别获得初值12,15,18。调用对象既可以通过对象名,也可以通过指针。
在执行new运算时,如果内存量不足,无法开辟所需的内存空间,目前大多数C++编译系统都使new返回一个0指针值。只要检测返回值是否为0,就可判断分配内存是否成功。
ANSI C++标准提出,在执行new出现故障时,就“抛出”一个“异常”,用户可根据异常进行有关处理。但C++标准仍然允许在出现new故障时返回0指针值。当前,不同的编译系统对new故障的处理方法是不同的。
在不再需要使用由new建立的对象时,可以用delete运算符予以释放。如
delete pt;
//释放pt指向的内存空间
这就撤销了pt指向的对象。此后程序不能再使用该对象。
如果用一个指针变量pt先后指向不同的动态对象,应注意指针变量的当前指向,以免删错了对象。在执行delete运算符时,在释放内存空间之前,自动调用析构函数,完成有关善后清理工作。
#include <iostream>
using namespace std;
void main01()
{
int *p = (int *)malloc(sizeof(int));
*p = 10;
delete p;
int *p2 = new int;
*p2 = 20;
free(p2);
int *p3 = new int(30);
printf("*p3:%d \n", *p3);
free(p3);
cout<<"hello..."<<endl;
system("pause");
return ;
}
void main02()
{
int *p = (int *)malloc(sizeof(int) * 10);
p[0] = 1;
delete[] p;
int *pArray = new int[10] ;
pArray[1] = 2;
free(pArray);
char *pArray2 = new char[25] ;
delete [] pArray2;
cout<<"hello..."<<endl;
system("pause");
return ;
}
class Test
{
public:
Test(int _a)
{
a = _a;
cout<<"构造函数执行" <<endl;
}
~Test()
{
cout<<"析构函数执行" <<endl;
}
protected:
private:
int a;
};
void main()
{
Test *pT1 = (Test *)malloc(sizeof(Test));
delete pT1;
Test *pT2 = new Test(10);
free(pT2);
cout<<"hello..."<<endl;
system("pause");
}