C++03

Day03 总结

构造与析构

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 MyClass
{
public:

//1.构造函数的写法
//没有返回值 函数名与类名相同
//可以有参数,可以重载
//由编译器自动调用,不需要手动调用
//而且编译器只会调用一次
MyClass()
{
cout<<"MYClASS的构造函数的调用"<<endl;
}
//2.析构函数的写法
//没有返回值,不写void 函数名与类名相同 在函数名前加~
//且编译器只会调用一次
~MyClass()
{
cout<<"MYCLASS的析构函数的调用"<<endl;
}
};
void test01()
{
MyClass myClass;
}
int main()
{
test01();
MyClass myClass;//在main函数结束后析构
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
//1.分类
//按照参数进行分类 有参构造函数 无参构造函数(默认)
//按照类型进行分类 普通构造函数 拷贝构造函数
class Person
{
public:
Person()
{
cout<<"Person 的默认构造函数的调用"<<endl;

}
//有参构造
Person(int age)
{
m_Age = age;
cout<<"Person 的有参构造函数调用"<<endl;
}
//拷贝构造
Person (const Person &p)// 类名(const 类名 &aa)
{
cout<<"拷贝构造函数的调用"<<endl;
m_Age = p.m_Age;
}
~Person()
{
cout<<" 析构函数的调用"<<endl;
}
int m_Age;
};
//2.调用
void test01()
{
//无参的构造函数
Person p;

//有参的构造函数,用括号
Person p2(10);

//拷贝构造函数
Person p3(p2);
//显示法
Person p4 = Person(10);//有参
Person p5 = Person(p4);//拷贝

//注意
// Person p();//不可以用括号发,调用无参构造函数 原因Person p() 编译器认为是函数的声明
// Person(10);//匿名函数对象 特点:当前行执行完后系统就回收了
// Person(p5);//不能调用拷贝构造函数,来初始化匿名函数对象Person(p5)

//隐式法
Person p6 = 10;//等价于写了Person p6 = Person (10)
Person p7 = p6;
}

拷贝构造函数的应用

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
class Person {
public:
Person()
{
cout<<"Person 的默认构造函数的调用"<<endl;

}
//有参构造
Person(int age)
{
m_Age = age;
cout<<"Person 的有参构造函数调用"<<endl;
}
//拷贝构造
Person (const Person &p)// 类名(const 类名 &aa)
{
cout<<"拷贝构造函数的调用"<<endl;
m_Age = p.m_Age;
}
~Person()
{
cout<<" 析构函数的调用"<<endl;
}
int m_Age;
};
//1.
void test01()
{
Person p1(19);
Person p2(p1);
}
//2以值传递的方式,给函数的参数传值,调用拷贝构造函数
void doWork(Person p)
{

}
void test02()
{
Person p1;
doWork(p1);
}
//3. 以值的方式来返回局部对象
Person doWork2()
{
Person p1;
return p1;
}
void test03()
{
Person p = doWork2();
}

构造函数调用规则

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
class Person {
public:
Person()
{
cout<<"Person 的默认构造函数的调用"<<endl;

}
//有参构造
Person(int age)
{
m_Age = age;
cout<<"Person 的有参构造函数调用"<<endl;
}
// 拷贝构造
Person (const Person &p)// 类名(const 类名 &aa)
{
cout<<"拷贝构造函数的调用"<<endl;
m_Age = p.m_Age;
}
~Person()
{
cout<<" 析构函数的调用"<<endl;
}
int m_Age;
};
//1.系统会默认给一个类添加至少3个函数,默认构造函数,析构函数,拷贝构造函数

void test01()
{
Person p1(20);
Person p2(p1);
cout<<p2.m_Age<<endl;
}
// 2. 如果我们自己提供了有参构造的函数,那么系统就不会默认提供构造函数了;但是依然会提供拷贝构造函数
void test02()
{
Person p1(10);
Person p2;
Person p3(p1);
}
//3.如果我们自己提供了拷贝构造函数,那么系统就不会提供其他普通构造函数了
void test03()
{
Person p1;
}
  • 值得注意的是,当有参构造由默认参数的时候,不需要自己写无参构造也可以直接调用无参构造函数

深拷贝和浅拷贝

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
class Person
{
public:
Person(char *name ,int age)
{
cout<<"Person有参函数的调用"<<endl;
m_Name =(char*) malloc (strlen(name)+1);
strcpy(m_Name,name);
m_Age = age;
}
//如果不自己写拷贝函数,那么系统提供的拷贝函数只会做简单的值拷贝(浅拷贝),如果类中有属性开辟打了堆区,在释放时,由于浅拷贝问题导致堆区内容会重复释放,程序运行不了
Person (const Person &p)
{
m_Age = p.m_Age;
//利用深拷贝,解决拷贝带来的问题
m_Name = (char*)malloc(strlen(p.m_Name)+1);
strcpy(m_Name,p.m_Name);
}
~Person()
{
if(m_Name!= NULL)
{
cout<<"Person析构函数的调用"<<endl;
free(m_Name);
m_Name = NULL;
}
}
char *m_Name;
int m_Age;
};
void test01()
{
Person p1("Tom",18);
cout<<"p1的姓名"<<p1.m_Name<<"p1的年龄"<<p1.m_Age<<endl;

Person p2(p1);
cout<<"P2Name"<<p2.m_Name<<"p2Age"<<endl;
}

初始化列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person{
public:
// Person(int a,int b,int c)
// {
// m_A = a;
// m_B = b;
// m_C = c;
// }
Person (int a,int b,int c):m_A(a),m_B(b),m_C(c)
{
//相当于上面的几行代码
}
int m_A;
int m_B;
int m_C;
};
void test01()
{
Person p1(10,20,30);
//Person p1;
}

类对象作为类成员

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
class Phone{
public:
Phone(string pName)
{
cout<<"Phone ????????"<<endl;
m_PhoneName = pName;
}
string m_PhoneName;
~Phone()
{
cout<<"Phone ????????"<<endl;
}

};
class Game{
public:
Game(string gName)
{
cout<<"Game????????"<<endl;
m_GameName = gName;
}
~Game()
{
cout<<"Game????????"<<endl;
}
string m_GameName;
};
class Person
{
public:
Person(string name,string pName,string gName):m_Name(name),m_Phone(pName),m_Game(gName){cout<<"Person????????"<<endl;}
~Person()
{
cout<<"Person????????"<<endl;
}
string m_Name;
Phone m_Phone;
Game m_Game;
};
void test01()
{
Person p("??","APPLE","????");
}

Explicit关键词

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
class MyString {
public:
MyString(char *string1)
{

}
//explicit 关键词用途:防止隐式类型转换来初始化对象;
explicit MyString(int len)
{
m_Len = len;
}
char *m_Str;
int m_Len;
};

MyString::MyString(const MyString &str) {

}

void test01()
{
MyString str = "abc";
MyString str2(10);
MyString str4 = MyString(10);
}

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
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
//new以后就不用malloc代码了
//Person *person = new Person
class Person {
public:
Person()
{
cout<<"Person 的默认构造函数的调用"<<endl;

}
//有参构造
Person(int age)
{
m_Age = age;
cout<<"Person 的有参构造函数调用"<<endl;
}
// 拷贝构造
Person (const Person &p)// 类名(const 类名 &aa)
{
cout<<"拷贝构造函数的调用"<<endl;
m_Age = p.m_Age;
}
~Person()
{
cout<<" 析构函数的调用"<<endl;
}
int m_Age;
};
//1.区别
//new 是一个运算符 malloc是一个库函数
//malloc返回值是void* new 返回出来的是new出来的对象的指针
//malloc需要判断是否开辟成功,new内部做好了这种操作(内部会malloc)
//malloc 不会调用构造函数,而new 调用了构造函数
//malloc对应的释放时free,而new对应的释放时delete;

void test01()
{
// Person p1; //在栈上
Person *person = new Person;//默认
Person *person2 = new Person(10);//有参构造
Person *person3 = new Person(*person2);//拷贝构造
//释放出new出来的对象
delete(person);
delete (person2);
delete(person3);
}
//2.注意事项
//不要用void * 去接受new出来的对象,原因是不能够释放
//3.利用new去创建数组
void test03()
{
// int *pInt = new int [10];
// char *pchar = new char[10];
//用new在"堆区"创建数组,类中必须要存在默认构造函数,否则无法创建
Person *persons = new Person[10];
//在栈上创建数组时,那么可以指定利用哪个构造函数来初始化对象
// Person person2[10] = {Person(10),Person(10),Person(10)};
//如果是数组的话,要在delete后加上[]
delete []persons;
}
-------------本文结束,感谢您的阅读-------------