C到C++ 快速过度 C 结构体到类.docx
《C到C++ 快速过度 C 结构体到类.docx》由会员分享,可在线阅读,更多相关《C到C++ 快速过度 C 结构体到类.docx(10页珍藏版)》请在冰豆网上搜索。
![C到C++ 快速过度 C 结构体到类.docx](https://file1.bdocx.com/fileroot1/2023-7/10/0831f813-5c0b-41e8-a330-11fc822d727c/0831f813-5c0b-41e8-a330-11fc822d727c1.gif)
C到C++快速过度C结构体到类
类”这个概念对C++来说意义非凡,与面向对象密不可分。
从这个概念开始,C++比C复杂的一面越加凸显。
还记得C语言中的结构体么?
structPoint{
doublex;
doubley;
};
上面的代码是一个“结构体模版”,我们利用它创建了一个叫做Point的类型。
在这之后,我们就可以像声明基本类型的变量一样声明Point类型:
Pointob;
ob叫做结构体Point的一个“实例”。
而当我们intn;的时候,会讲n是int类型的一个“变量”。
结构体是一种复合类型,但是它和同样身为复合类型的数组不同:
--数组操作技巧-->
charname[20];
我们这样就声明了一个数组,并且每个name[i](0<=i<20)都是一个独立的char类型的变量。
它们被称为数组的“元素”。
值得一提的是,同一个数组的各个元素所占用的内存空间是连续的。
这使得我们在遍历(检索)整个数组的时候,速度非常的快:
intline[]={2,5,6,7,8,12,-5,-32}; //1
intlen=sizeof(line)/sizeof(int); //2
for(inti=0;i line[i]=-line[i];
上述语句遍历这个数组,并且将每个元素的值都取反。
第1个语句说明,数组可以根据你声明时填写的数据自动分配大小,但是一旦分配,数组的大小就定了。
第2个语句可以直接确定数组中元素的个数,这样就无需一个个数了。
sizeof是一个操作符,用法类似于函数。
当参数是数组名时,将得到整个数组所占内存的字节数;而当参数是类型时,得到的是该类型变量的字节数。
而对于字符串数组,初始化有更方便的方法:
charname[]="AlwaysLaugh";
这样name就会被自动分配成长度13的数组(别忘了'\0')。
除了之前介绍的使用sizeof操作符取元素个数的方法以外,头文件(C++中shi)中的strlen函数可以更方便地取字符串长度:
charname[]="AlwaysLaugh";
intlen=strlen(name);
for(inti=0;i name[i]++;
这个代码会把name数组的的每个元素在字符表中“后移”一位。
需要注意的是,strlen只能处理char的字符串数组,对int等不适用。
并且它以字符串末尾的'\0'字符为结束标志,因此取到的往往不是数组大小。
--类-->
现在介绍C++中的“类”这个概念,它和结构体极其相似。
我们先写一个使用结构体的程序:
#include
usingnamespacestd;
structPoint{ // 1结构体的模版
doublex; // 成员
doubley;
};
intmain()
{
Pointp; // 2结构体的声明
p.x=3.2; // 3结构体的使用
p.y=8.9;
cout<<"("<
return0;
}
结构体的模版和函数的定义性质相同(之后介绍的“类”也同样),只是规定了这个结构体/类的内部结构和工作原理,并不分配内存。
我们在使用结构体对象的时候,总是使用它的成员。
“.”这个操作符用来连接结构体的实例和它的成员。
实例的名称可以自由去定义,就像变量名一样,但是相同类型的实例总是拥有的成员确是完全相同的,都和模版中的一致。
即利用相同模版初始化的实例都具有相同的成员。
而当将类引入时,会发生较大的变化:
#include
usingnamespacestd;
classPoint{
private:
doublex;
doubley;
public:
setPoint(doublem,doublen){
x=m;y=n;
}
printPoint(){
cout<<"("< }
};
intmain()
{
Pointp;
p.setPoint(3.2,8.9);
p.printPoint();
return0;
}
这个程序和用结构体的效果是相同的,但是复杂的地方集中在了类的模版定义部分。
出现了很多陌生的东西,private,public,甚至还有函数。
这是因为,对于类而言,不仅变量可以作为成员,函数也可以。
而当你想要在主函数中使用如下语句时:
p.x=2.2;p.y=1.1;
你会发现这个不允许的。
原因就在于关键字private(私有的),它将x和y成员保护了起来,使它们在“模版区”之外不能出现。
注意是“不能出现”,而不仅是“不能赋值”。
这意味着cout<
关键字public(公有的)定义的成员可以暴露给外界,正如主函数中的p.setPoint(3.2,8.9);和p.printPoint();一样。
把x和y设置为私有成员是为了数据的安全性:
intmain()
{
Pointp;
p.setPoint(3.2,8.9);
p.printPoint();
return0;
}
这是刚刚的主函数,我们从中根本看不出p这个类含有哪种或者多少个私有成员,更不知道成员叫做x/y。
它们确实可以在类模版中看到,但是在工程中我们使用的类,大多数是见不到类模版的,他们存放在不同的文件中。
这样,我们只需要知道类的公有成员函数接受哪些变量,起到哪些作用,学会调用即可。
至于具体细节,内部逻辑,我们不需要知道。
这就是“封装”,C++的三大特性之一。
正如你看到的,私有成员变量可以在成员函数中直接出现,因为它们处于同一个作用域中(类模版的花括号)。
有私有成员函数吗?
当然有。
它可以供其他私有成员函数或者公有成员函数去调用。
总之,只有公有成员(可以出现在“模版区”之外)才会和“.”连用。
因为一个“实例”的声明和使用都是在外界的。
简而言之:
成员包括私有成员和公有成员。
成员分为成员变量和成员函数。
--构造函数-->
classPoint{
private:
doublex;
doubley;
public:
Point(){
}
Point(doublem,doublen){
x=m;y=n;
}
setPoint(doublem,doublen){
x=m;y=n;
}
printPoint(){
cout<<"("< }
};
仍然是那个类,多了两个比较怪异的函数。
没错,函数的名称和类名称一样,并且他们不含返回值。
有了它们,我们便可以在主函数中这样子声明p。
intmain()
{
Pointp(3.2,8.9);
p.printPoint();
return0;
}
构造函数是在初始化实例的过程中调用的,这样我们可以在初始化的同时给成员赋值,而setPoint用来改变成员的值。
为什么Point函数声明了两次?
还记得函数重载么?
我们重载了它。
这样我们既可以在声明实例的时候初始化它,也可以不这么做。
因为构造函数总是会执行的。
Pointp;和Pointp();丝毫没有区别。
--些许复杂的示例程序-->
#include
#include
usingnamespacestd;
structFriend{
charname[20];
Friend*nest;
Friend(char*pn){
strcpy(name,pn);
nest=NULL;
}
};
structFriendList{
Friend*head;
Friend*mov;
intnumber;
boolnone;
FriendList(Friend*pri){
head=mov=pri;
number=1;
none=0;
}
voidReTop(){
mov=head;
none=0;
}
voidBeFriend(Friend*someone){
Friend*temp=mov->nest;
mov->nest=someone;
someone->nest=temp;
number++;
}
boolQue(Friend*f){
if(none){
cout<<"Yougotnofriends.\n\n";
ReTop();
return0;
}
if(!
mov->nest)none=1;
charch;
while(getchar()!
='\n')continue;
cout<<"Doyouwangtomakefriendswith"
<name<<"?
"< <<"YtoYESandNtoNO"< cin>>ch;
if(ch=='Y'){
cout<<"You'vebeenfriendwith"<name<<"!
\n\n";
BeFriend(f);
ReTop();
return0;
}else{
mov=mov->nest;
return1;
}
}
voidEnd()
{
Friend*temp;
while(number--){
temp=head->nest;
delete(head);
head=temp;
}
}
};
intmain()
{
charname[20]="AlwaysLaugh";
Friend*Me=newFriend(name);
FriendListmyFriend(Me);
intT=4;
while(T--){
cout<<"Enteryourname:
";
cin>>name;
Friend*you=newFriend(name);
cout<<"Hello"<name<<"!
"< while(myFriend.Que(you));
}
return0;
}
这个示例程序对刚接触C++的人来说难度很大,接近一个课设。
因为类的内部联系复杂。
并且还用到了动态内存分配(比如new和delete操作符),和链表的内容(这些内容对大家来说是陌生的)。
这是一个交朋友的程序,大家不妨编译运行一下,看看效果,再尽力把代码搞懂(为了避免越界访问,请不要输入得太古怪)。