C++记忆恢复集要之二:类与对象
类和对象
1. 从结构体到类
结构体: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using namespace std;
struct Person
{
string name;
int id;
int score;
void PrintInfo(){
cout<<name<<'\t'<<id<<'\t'<<score<<endl;
}
};
int main(){
Person Eden;
Eden.name="MrEason";
Eden.id=110;
Eden.score=123;
Eden.PrintInfo();
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using namespace std;
class Person
{
public:
string name;
int id;
int score;
void PrintInfo(){
cout<<name<<'\t'<<id<<'\t'<<score<<endl;
}
};
int main(){
Person Eden;
Eden.name="MrEason";
Eden.id=110;
Eden.score=123;
Eden.PrintInfo();
return 0;
}
2. 类的多文件编译
根据不同的平台搭建多文件编译环境,目的是为编译器找到需要编译的cpp文件和头文件。以VsCode为例:
1.
在配置文件c_cpp_properties.json检查头文件路径:
1
2
3"includePath": [
"${workspaceFolder}/**",
],1
2
3
4
5
6
7
8
9
10
11"args": [
"-fdiagnostics-color=always",
"-g",
//"${file}", //当前文件
"${workspaceFolder}\\main.cpp",//多文件编程
"${workspaceFolder}\\person.cpp",
"-I",
"C:/Users/24364/C_git/"//头文件所在文件夹
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe"
],1
2
3
4
5
6
7
8
9
10
11
12
13//person.h
class Person
{
public:
std::string name; //string需要std支持
int id;
int score;
void PrintInfo();
};1
2
3
4
5
6
7
8
9//person.cpp
using namespace std;
void Person::PrintInfo(){
cout<<name<<'\t'<<id<<'\t'<<score<<endl;
}1
2
3
4
5
6
7
8
9
10
11
12//main.cpp
using namespace std;
int main(){
Person Eden;
Eden.name="MrEason";
Eden.id=110;
Eden.score=1234;
Eden.PrintInfo();
return 0;
}
3. 类的初始化与赋值
公有的对象可以在类外进行初始化,而私有对象无法直接初始化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using namespace std;
class Person
{
public:
std::string name;
int id;
int score;
void PrintInfo();
};
void Person::PrintInfo(){
cout<<name<<'\t'<<id<<'\t'<<score<<endl;
}
int main(){
Person Eden;
Eden={"MrEason",110,1234};//公有对象直接赋值初始化
// Eden.name="MrEason";
// Eden.id=110;
// Eden.score=1234;
Eden.PrintInfo();
return 0;
}
两种类成员实例化方法
1 | Person Ming =Eden;//1.调用拷贝构造函数创建 |
拷贝构造函数:本质上是一种值传递,将实例化Eden的成员逐一拷贝到新实例Ming中,这对普通变量是可行的,但是如果类中成员有指针变量,则会造成浅拷贝问题,也即两个指针变量同时指向一个地址,导致内存释放时如果释放两次会造成程序出错。
4. C++类三个自动调用的成员函数
1. 构造函数:
与类同名的函数,可重载,用于实例化对象时自动初始化。无参构造、两种有参传值方法、四种调用方法形式如下:
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
using namespace std;
class Person
{
public:
//无参构造函数和有参构造函数
Person(){
cout<<"This is a test"<<endl;
}
//直接传参:区分形参与类成员变量
Person(string name,int id,int score){
pname=name;
pid=id;
pscore=score;
cout<<pname<<'\t'<<pid<<'\t'<<pscore<<endl;
}
//链表传参:可以混用形参与类成员变量
// Person(string pname,int pid,int pscore):
// pname(pname),pid(pid),pscore(pscore){
// cout<<pname<<'\t'<<pid<<'\t'<<pscore<<endl;
// }
string pname;
int pid;
int pscore;
//void PrintInfo();
};
// void Person::PrintInfo(){
// cout<<pname<<'\t'<<pid<<'\t'<<pscore<<endl;
// }
int main(){
//1.隐式调用
Person Eden; //自动调用无参构造
Person Ming("Mike",12,123); //自动调用有参构造
//2.显式调用
Person Eden1=Person();
Person Ming1=Person("Mike",12,123);
//3.动态开辟空间调用
Person *a=new Person; //无参
Person *b=new Person(); //无参
Person *c=new Person("Mike",12,123); //有参
//4.匿名对象调用:生存周期很短,定义开辟、执行完毕自动释放,常用于临时对象的赋值
Person();
Person("Mike",12,123);
}
2. 析构函数:
波浪线~+类名标识一个析构函数,析构函数没有参数,也没有返回值,void不写,唯一且不能重载,用于释放成员变量的空间。
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
using namespace std;
class Person
{
public:
//无参构造函数和有参构造函数
Person(){
cout<<"This is a test"<<endl;
}
Person(string name,int id,int score){
pname=name;
pid=id;
pscore=score;
cout<<pname<<'\t'<<pid<<'\t'<<pscore<<endl;
}
//析构函数
~Person(){
cout<<"This is a Destructor"<<endl;
}
string pname;
int pid;
int pscore;
//void PrintInfo();
};
// void Person::PrintInfo(){
// cout<<pname<<'\t'<<pid<<'\t'<<pscore<<endl;
// }
int main(){
Person Eden; //自动调用无参构造
Person Ming("Mike",12,123); //自动调用有参构造
return 0;
}
结果:This is a test Mike 12 123 This is a Destructor This is a Destructor //两个对象销毁两次均调用
堆区、栈区、全局区、静态区类对象的析构函数调用时机:
1 |
|
结果This is a test //全局变量实例化 This is a test //test普通变量无参 Mike 12 123 //test普通变量有参 This is a test //静态变量 static0x408080 //静态变量地址 This is a test //堆区 This is a Destructor! //普通无参触发 0x61fd50 This is a Destructor! //普通有参触发 0x61fd80 Flag1 This is a Destructor! //静态变量触发 0x408080 This is a Destructor! //全局区触发 0x408040
结果综述:普通函数类对象的变量存储在栈区,在完成函数执行即释放内存,静态变量在return 0前进行释放,全局变量在程序执行完成,return 0时释放,堆区开辟的空间可以手动delete释放,如果没有则在程序结束以后才释放内存,因为程序结束在前,故看不到析构函数调用现象了。
3. 拷贝构造函数:
与类同名,但接受的参数是本类对象参数,系统的拷贝构造函数底层实现类似代码所示,通过引用保证是值传递(而不会开辟新的空间)。而系统的构造函数、析构函数默认均为无参。
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
using namespace std;
class Person
{
public:
//无参构造函数和有参构造函数
Person(){
cout<<"This is a test"<<endl;
}
Person(string name,int id,int score){
pname=name;
pid=id;
pscore=score;
cout<<pname<<'\t'<<pid<<'\t'<<pscore<<endl;
}
//析构函数
~Person(){
cout<<"This is a Destructor"<<endl;
}
//拷贝构造函数
Person(const Person &obj){
cout<<"This is a Copy constructor"<<endl;
pname=obj.pname;
pid=obj.pid;
pscore=obj.pscore;
cout<<pname<<'\t'<<pid<<'\t'<<pscore<<endl;
}
string pname;
int pid;
int pscore;
//void PrintInfo();
};
// void Person::PrintInfo(){
// cout<<pname<<'\t'<<pid<<'\t'<<pscore<<endl;
// }
int main(){
Person Eden; //自动调用无参构造
Person Ming("Mike",12,123); //自动调用有参构造
Person Yao=Ming; //自动调用拷贝构造函数
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
using namespace std;
class Person
{
public:
//无参构造函数和有参构造函数
Person(){
cout<<"This is a test"<<endl;
}
//直接传参:区分形参与类成员变量
Person(string name,int id,int score){
pname=name;
pid=id;
pscore=score;
//cout<<pname<<'\t'<<pid<<'\t'<<pscore<<endl;
}
Person(const Person &obj){
cout<<"This is a Copy Constructor"<<endl;
pname=obj.pname;
pid=obj.pid;
pscore=obj.pscore;
//cout<<pname<<'\t'<<pid<<'\t'<<pscore<<endl;
}
string pname;
int pid;
int pscore;
};
//类作为形参
void printInfo(Person obj){
cout<<obj.pname<<'\t'<<obj.pid<<'\t'<<obj.pscore<<endl;
}
//类作为返回对象
Person Return_OBJ(){
static Person Ming; //static要保证类存活到运行完成test
return Ming;
}
void test(){
Person Eden("Mike",112,122);
printInfo(Eden);
Return_OBJ();
}
int main(){
test();
return 0;
}
构造、析构、拷贝构造函数解决类指针变量使用问题
构造函数为大批量的类实例化提供了便利,但在类中如果涉及指针变量在堆区开辟空间(如char*字符串等),应该通过手动方式进行释放,否则会导致大量的空间被占用,析构函数就完成了这个任务,但系统的拷贝构造函数会引起前文所说的浅拷贝问题,导致析构函数执行异常,因此应该以深拷贝方式进行调用。
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
using namespace std;
class Person
{
public:
//无参构造函数
Person(){
name=NULL;
slga=NULL;
id=0;
score=0;
cout<<"This is non-parameter constructor"<<endl;
}
//有参构造函数
Person(char *pname,char *pslga,int pid,int pscore)
{
name=new char[strlen(pname)+1];
strcpy(name,pname);
slga=new char[strlen(pslga)+1];
strcpy(slga,pslga);
id=pid;
score=pscore;
cout<<"This is parameter constructor"<<endl;
}
//析构函数
~Person(){ //假如是无参构造,堆区为空,则无需释放内存
if(name!=NULL){
delete []name;
name=NULL;
cout<<"This is a name-Destructor"<<endl;
}
if(slga!=NULL){delete []slga;
slga=NULL;
cout<<"This is a slga-Destructor"<<endl;
}
}
Person(const Person &obj){
cout<<"This is a Copy Constructor"<<endl;
//深拷贝
name=new char[strlen(obj.name)+1];
strcpy(name,obj.name);
slga=new char[strlen(obj.slga)+1];
strcpy(slga,obj.slga);
id=obj.id;
score=obj.score;
}
void printInfo(){
cout<<name<<'\t'<< slga<<'\t'<<id<<'\t'<<score<<endl;
}
private:
char *name;
char *slga;
int id;
int score;
};
int main(){
//C++更建议使用string,string本身底层使用深拷贝,字符串赋予char*会报警告
Person Eden("Mike","Study is Happy",12,123);
Eden.printInfo();
//拷贝test
Person Ming=Eden;
Ming.printInfo();
return 0;
}
5. this指针
类对象实例化后都会将自己地址传入大多数的成员函数中(不是全部),方便调用:如通过this可以特指实例化的成员而与形参区分。this地址与实例化类地址将保持一致:
1
2
3
4
5
6
7
8
9
10
11//有参构造函数
Person(char *name,char *slga,int pid,int score)
{
this->name=new char[strlen(name)+1];
strcpy(name,pname);
this->slga=new char[strlen(slga)+1];
strcpy(slga,slga);
this->id=pid;
this->score=score;
cout<<"This is parameter constructor"<<endl;
}
6. 类对象数组
进行局部初始化:初始化部分调用有参构造函数,其余部分调用的是无参构造函数。
1
Person Array[6];// 定义对象数组
7. 类成员对象
另一个类作为该类的成员变量,称类成员对象。实例化时,首先调用类成员对象的构造函数,后调用本类的构造函数;首先调用本类的析构函数,后再调用类成员对象的析构函数。假如类成员对象的成员变量在原类中被赋予私有权限,则一般通过原类的公有函数进行初始化操作。
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
using namespace std;
class Pysicque
{
public:
Pysicque(){
cout<<"This is a new non-parameter constructor"<<endl;
}
//同名链表传参
Pysicque(int height,int weight):
height(height),weight(weight)
{
cout<<"This is a new parameter constructor "<<endl;
}
~Pysicque(){
cout<<"This is a new destructor"<<endl;
}
//两个公有函数操作私有成员
void set_psyinfo(int height,int weight){
this->height=height;
this->weight=weight;
}
void printInfo(){
cout<<height<<'\t'<<weight<<'\t'<<endl;
}
private:
int height;
int weight;
};
class Person
{
public:
//无参构造函数
Person(){
name="";//空
slga="";
id=0;
score=0;
cout<<"This is non-parameter constructor"<<endl;
}
//有参构造函数
Person(string name,string slga,int pid,int score,int height,int weight)
{
this->name=name;
this->slga=slga;
this->id=pid;
this->score=score;
Pys.set_psyinfo(height,weight);
cout<<"This is parameter constructo!"<<endl;
}
//析构函数
~Person(){ //假如是无参构造,堆区为空,则无需释放内存
cout<<"This is a destructor!"<<endl;
}
// Person(const Person &obj){
// cout<<"This is a Copy Constructor"<<endl;
// name=obj.name;
// slga=obj.slga;
// id=obj.id;
// score=obj.score;
// }
void printInfo(){
cout<<name<<'\t'<< slga<<'\t'<<id<<'\t'<<score<<endl;
Pys.printInfo();
}
private:
string name;
string slga;
int id;
int score;
Pysicque Pys;
};
int main(){
Person Eden("Mike","I hate study",1,100,200,100);// 定义对象数组
Eden.printInfo();
return 0;
}
8. 常函数和常对象
常函数、常对象是被const修饰的成员函数和实例化类,有以下特点:
常函数:一般用于获取成员变量的值,而不进行修改,如果修改必须用mutable关键字修饰对应成员对象;
常对象:常对象可以正常调用构造函数,但无法调用普通的成员函数,只能调用常函数;无法修改普通成员变量,只能修改公有且被mutable关键字修饰的成员变量。
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
using namespace std;
class Person
{
public:
//无参构造函数
Person(){
name="";//空
slga="";
id=0;
score=0;
cout<<"This is non-parameter constructor"<<endl;
}
//有参构造函数
Person(string name,string slga,int pid,int score)
{
this->name=name;
this->slga=slga;
this->id=pid;
this->score=score;
cout<<"This is parameter constructo!"<<endl;
}
//常函数
void printInfo() const
{
score=100;
cout<<name<<'\t'<< slga<<'\t'<<id<<'\t'<<score<<endl;
}
private:
string name;
string slga;
int id;
mutable int score; //常函数要修改的值必须用mutable修饰
};
int main(){
Person Eden("Mike","I hate study",1,99);//
Eden.printInfo();
//常对象
const Person const_Eden;
const_Eden.printInfo();
const Person const_Eden1("Mike","I hate study",1,98);
const_Eden1.printInfo();
return 0;
}
9. 静态成员变量和静态成员函数
静态成员变量
- 静态成员变量必须在类外进行声明和初始化才能在类内正常使用。
- 静态成员变量归属于类而不是对象,类的所有实例化对象共用一个静态成员变量,所以一般赋予公有权限,通过类名+域解析符在类外来直接操作。
静态成员函数:
- 静态成员函数内不能使用this指针;
- 静态成员函数只能操作静态成员变量,不能操作普通成员变量;
- 静态成员函数同样属于类而不属于对象,通过类名+域解析符调用。
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
using namespace std;
class Person
{
public:
static int num;//类内声明:静态成员变量
//无参构造函数
Person(){
name="";//空
slga="";
id=0;
score=0;
cout<<"This is non-parameter constructor"<<endl;
}
//有参构造函数
Person(string name,string slga,int pid,int score)
{
this->name=name;
this->slga=slga;
this->id=pid;
this->score=score;
cout<<"This is parameter constructo!"<<endl;
}
//静态成员函数:不能含this,不能含普通成员变量
static void test(){
cout<<"静态变量起始值:"<<num<<endl;
Person::num=999;
cout<<"静态变量更新值:"<<num<<endl;
}
void printInfo()
{
cout<<name<<'\t'<<slga<<'\t'<<id<<'\t'<<score<<endl;
}
private:
string name;
string slga;
int id;
int score; //常函数要修改的值必须用mutable修饰
};
int Person::num=88;//静态变量:一定要在类外初始化,不能声明static
int main(){
Person::test(); //类 调用 静态成员函数
Person Eden;
Person Ming;
Eden.num=99; //类对象 修改 静态变量
cout<<Ming.num<<endl;//其他对象会同步修改
//Person::num=99;//类访问也是修改
Eden.test();//对象 调用 静态成员函数
cout<<Ming.num<<endl;
return 0;
}
10. 友元
10.1 友元函数(全局)
在类内声明一个friend修饰的函数称为该类的友元函数,友元函数在类外也可对本类的私有成员进行访问和操作:
1
friend void test(parameter);
10.2 友元类
在类内声明友元类,友元类的所有成员函数都可以对该类的所有成员进行访问和操作,但不能通过友元类在类外直接对该类的私有成员进行访问和操作。例如,B类被声明为A类的友元,只能在B类的成员函数实现调用A类的私有成员变量,而不能类外实例化B类后,通过B访问A的成员变量。
1
friend class test;
10.3 友元成员函数
一个类的成员函数可在另一个类中被声明成友元函数,该成员函数允许访问和操作另一个类的私有成员,比起友元类这种方法具有更高保护性,但有繁琐的顺序要求:
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
using namespace std;
//声明第一个类:供给成员函数的
class Person
{
public:
void printInfo(); //要设置成另一个类的友元成员函数只声明不实现
Person(string name,string slga,int pid,int score)
{
this->name=name;
this->slga=slga;
this->id=pid;
this->score=score;
cout<<"This is parameter constructo!"<<endl;
}
private:
string name;
string slga;
int id;
int score;
};
//第二个类:通过上一个类某个成员函数访问该类的私有成员
class Pysicque
{
friend void Person::printInfo();//声明友元函数
public:
Pysicque(int height,int weight):
height(height),weight(weight){cout<<"This is a new parameter constructo!"<<endl; }
void Pys_printInfo(){
cout<<height<<'\t'<<weight<<'\t'<<endl;
}
private:
int height;
int weight;
};
//友元函数类外实现
void Person::printInfo(){
Pysicque Pys(100,100);
cout<<name<<'\t'<<slga<<'\t'<<id<<'\t'<<score<<endl;
cout<<Pys.height<<'\t'<<Pys.weight<<'\t'<<endl;
}
int main(){
//测试友元函数能否获取信息
Person Eden("Mike","I hate study",1,100);
Eden.printInfo();
return 0;
}
11. 运算符重载
C++支持运算符重载,即不同的数据类型可以根据函数定义进行运算,适应特殊的计算需求。运算符重载的本质是更简洁的函数调用,增加代码易读性,
一般重载函数格式为: 1
数据类型 operator@(parameter){...}//@指代需要重载的运算符
不支持重载运算符: 成员访问运算符(.)、域解析符(::)、长度运算符(sizeof)、成员指针运算符(->*、.*)、条件运算符(?:)、预处理运算符(#)
11.1 公有成员实现运算符重载
1 |
|
结果:m=0、n=2 后缀++是m先接收后增值,n是先增值后接收输出
11.2 私有成员实现运算符重载
方法一:类内公有函数
类内实现本身就包含一个类对象,this指针可以引用,因此比外部实现可减少一个形参,如obj+obj只需要传入一个Person &obj作为形参,obj++则无需传入Person类。
方法二:友元函数
类中声明即可,不赘述。 1
2friend int operator++(Person &obj,int);
friend int operator++(Person &obj);
12. 代码实战:类与运算符重载实现string类
字符串的char*、char[]类型使用麻烦,且容易造成非法的内存操作,因此C++封装了一种string类,大大提高了使用字符串的鲁棒性。本代码目的根据前述知识模拟封装一个简化的“string类”,具备赋值、打印、合并、比较等简单功能。采用多文件编译环境方便移植,参考如下:
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//Testring.h
using namespace std;
class Testring{
public:
Testring(){
T_string=NULL;
size=0;
}
Testring(char *str){
this->size=strlen(str);
this->T_string=new char[strlen(str)+1];
strcpy(T_string,str);
}
char *T_string; //字符串内容
int size; //字符串长度
void printString(); //字符串打印
Testring& operator=(Testring& tempstr); //串类赋值
Testring& operator=(char* tempstr); //常量赋值
char& operator[](int index); //中括号重载,字符串索引寻址
Testring& operator+(Testring &tempstr); //加号重载,字符串追加
Testring& operator+(char *tempstr); //加号重载,字符串追加
bool operator==(Testring &tempstr);//字符串类间比较
bool operator==(char *tempstr); //字符串与字符串常量比较
};
ostream& operator<<(ostream& os,Testring& str); //全局的运算符重载函数,所以需要两个参数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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122//Testring.cpp
using namespace std;
//打印长度、字符串内容
void Testring::printString(){
cout<<"string:"<<T_string<<endl;
cout<<"size:"<<size<<endl;
}
//输出流重载打印
ostream& operator<<(ostream& os,Testring& str){
cout<<"string:"<<str.T_string<<endl;
cout<<"size:"<<str.size<<endl;
return cout; //返回cout的目的是能实现连续输出,cout<<xxx<<xxx...
}
//类对象传递重载
Testring& Testring::operator=(Testring& tempstr){
if(this==&tempstr){ //A1:同地址不传递
return *this;
}
else{
if(this->T_string!=NULL){
delete []this->T_string; //Q1:直接delete影响了自身传值
this->T_string=new char[tempstr.size+1];
strcpy(this->T_string,tempstr.T_string);
this->size=tempstr.size;
}
else{
this->T_string=new char[tempstr.size+1];
strcpy(this->T_string,tempstr.T_string);
this->size=tempstr.size;
}
return *this;
}
}
//字符串传递重载
Testring& Testring::operator=(char* tempstr){
if(this->T_string!=NULL){
delete []this->T_string;
this->T_string=new char[strlen(tempstr)+1];
strcpy(this->T_string,tempstr);
this->size=strlen(tempstr);
}
else{
this->T_string=new char[strlen(tempstr)+1];
strcpy(this->T_string,tempstr);
this->size=strlen(tempstr);
}
return *this;
}
//索引寻值重载
char& Testring::operator[](int index){
if(index>=0&&index<size){
return T_string[index];
}
else{
cout<<"Sorry,out of Index!"<<endl;
}
}
//字符串增重载
Testring& Testring::operator+(Testring& tempstr){
if(this->T_string!=NULL){
char *temp=new char[this->size+1];
strcpy(temp,this->T_string);
delete []this->T_string;
this->T_string=new char[this->size+tempstr.size+1];
strcpy(this->T_string,temp);
strcat(this->T_string,tempstr.T_string);
this->size+=tempstr.size;
delete []temp;
}
else{
this->T_string=new char[tempstr.size+1];
strcpy(this->T_string,tempstr.T_string);
this->size+=tempstr.size;
}
return *this;
}
Testring& Testring::operator+(char *tempstr){
if(this->T_string!=NULL){
char *temp=new char[this->size+1];
strcpy(temp,this->T_string);
delete []this->T_string;
this->T_string=new char[this->size+strlen(tempstr)+1];
strcpy(this->T_string,temp);
delete []temp;
strcat(this->T_string,tempstr);
this->size+=strlen(tempstr);
}
else{
T_string=new char[strlen(tempstr)+1];
strcpy(T_string,tempstr);
this->size+=strlen(tempstr);
}
return *this;
}
bool Testring::operator==(Testring &tempstr){
if(tempstr.size!=this->size){
return false;
}
else{
if(tempstr.T_string!=this->T_string){return false;}
else return true;
}
}
bool Testring::operator==(char *tempstr){
if(strlen(tempstr)!=this->size){
return false;
}
else{
if(strcmp(tempstr,this->T_string)!=0){
cout<<"sasa"<<strcmp(tempstr,this->T_string)<<endl;
return false;} //strcmp判断相等返回0,不等返回-1;
else return true;
}
}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//main.cpp
using namespace std;
//主测试函数
int main(){
//打印
Testring string1("Hello World");
Testring string4("Hello Eden");
string1.printString(); //函数打印
cout<<string1<<string4; //输出流打印
//寻值
cout<<"-------------寻值------------------"<<endl;
cout<<string1[2]<<endl;
//常量赋值
cout<<"--------------常量赋值-----------------"<<endl;
char *test="Hello Eden";
Testring string2;
string2=test;
string2.printString();
string2=string2+"bye World";
string2.printString();
//类间赋值
cout<<"--------------类间赋值-----------------"<<endl;
Testring string3("Hello");
string3.printString();
string3=string3+string2+string1+string1;
string3.printString();
//字符串比较
cout<<"--------------字符串比较-----------------"<<endl;
cout<<(string3==string2)<<endl;
string3.printString();
cout<<(string3=="HelloHello Edenbye WorldHello WorldHello World")<<endl;
}