C到C++ 快速过度 C 结构体到类

还记得C语言中的结构体么?
struct Point{
    double x;
    double y;
};
上面的代码是一个“结构体模版”,我们利用它创建了一个叫做Point的类型。

在这之后,我们就可以像声明基本类型的变量一样声明Point类型:
Point ob;

ob叫做结构体Point的一个“实例”。

而当我们 int n; 的时候,会讲n是int类型的一个“变量”。

结构体是一种复合类型,但是它和同样身为复合类型的数组不同:

<!--数组操作技巧-->

char name[20];
我们这样就声明了一个数组,并且每个name[i](0 <=i < 20)都是一个独立的char类型的变量。它们被称为数组的“元素”。

值得一提的是,同一个数组的各个元素所占用的内存空间是连续的。

这使得我们在遍历(检索)整个数组的时候,速度非常的快:

int line[] = {2, 5, 6, 7, 8, 12, -5, -32};        // 1
int len = sizeof(line) / sizeof(int);            // 2
for(int i = 0; i < len; i++)
    line[i] = -line[i];

上述语句遍历这个数组,并且将每个元素的值都取反。

第 1 个语句说明,数组可以根据你声明时填写的数据自动分配大小,但是一旦分配,数组的大小就定了。

第 2 个语句可以直接确定数组中元素的个数,这样就无需一个个数了。
sizeof是一个操作符,用法类似于函数。当参数是数组名时,将得到整个数组所占内存的字节数;而当参数是类型时,得到的是该类型变量的字节数。

而对于字符串数组,初始化有更方便的方法:

char name[] = "Always Laugh";

这样name就会被自动分配成长度13的数组(别忘了‘\0‘)。

除了之前介绍的使用sizeof操作符取元素个数的方法以外,头文件<string.h>(C++中shi<cstring>)中的strlen函数可以更方便地取字符串长度:

char name[] = "Always Laugh";
int len = strlen(name);
for(int i = 0; i < len; i++)
    name[i]++;

这个代码会把name数组的的每个元素在字符表中“后移”一位。

需要注意的是,strlen只能处理char的字符串数组,对int等不适用。

并且它以字符串末尾的‘\0‘字符为结束标志,因此取到的往往不是数组大小。

<!--类-->

现在介绍C++中的“类”这个概念,它和结构体极其相似。

我们先写一个使用结构体的程序:

#include <iostream>

using namespace std;

struct Point{                //  1 结构体的模版

double x;        //  成员

double y;

};

int main()

{

Point p;                //  2 结构体的声明

p.x = 3.2;                 //  3 结构体的使用

p.y = 8.9;

cout << "(" << p.x << "," << p.y << ")" << endl;    // 结构体的使用

return 0;

}

结构体的模版和函数的定义性质相同(之后介绍的“类”也同样),只是规定了这个结构体/类的内部结构和工作远离,并不分配内存。

我们在使用结构体对象的时候,总是使用它的成员。“.”这个操作符用来连接结构体的实例和它的成员。

实例的名称可以自由去定义,就像变量名一样,但是相同类型的实例总是拥有的成员确是完全相同的,都和模版中的一致。

即利用相同模版初始化的实例都具有相同的成员。

而当将类引入时,会发生较大的变化:

#include <iostream>

using namespace std;

class Point{

private:

double x;

double y;

public:

setPoint(double m, double n){

x = m; y = n;

}

printPoint(){

cout << "(" << x << "," << y << ")" << endl;

}

};

int main()

{

Point p;

p.setPoint(3.2, 8.9);

p.printPoint();

return 0;

}

这个程序和用结构体的效果是相同的,但是复杂的地方集中在了类的模版定义部分。

出现了很多陌生的东西,private,public,甚至还有函数。

这是因为,对于类而言,不仅变量可以作为成员,函数也可以。

而当你想要在主函数中使用如下语句时:

p.x = 2.2; p.y = 1.1;

你会发现这个不允许的。

原因就在于关键字private(私有的),它将x和y成员保护了起来,使它们在“模版区”之外不能出现。

注意是不能出现,而不仅是不能赋值。这意味着 cout << p.x; 也是不允许的。

关键字public(公有的)定义的成员可以暴露给外界,正如主函数中的p.setPoint(3.2, 8.9);和p.printPoint();一样。

把x和y设置为私有成员是为了数据的安全性:

int main()

{

Point p;

p.setPoint(3.2, 8.9);

p.printPoint();

return 0;

}

这是刚刚的主函数,我们从中根本看不出p这个类含有哪种或者多少个私有成员,更不知道成员叫做x/y。

它们确实可以在类模版中看到,但是在工程中我们使用的类,大多数是见不到类模版的,他们存放在不同的文件中。

这样,我们只需要知道类的公有成员函数接受哪些变量,起到哪些作用,学会调用即可。至于具体细节,内部逻辑,我们不需要知道。

这就是“封装”,C++的三大特性之一。

正如你看到的,私有成员变量可以在成员函数中直接出现,因为它们处于同一个作用域中(类模版的花括号)。

有私有成员函数吗?当然有。它可以供其他私有成员函数或者公有成员函数去调用。

总之,只有公有成员(可以出现在“模版区”之外)才会和“.”连用。因为一个“实例”的声明和使用都是在外界的

简而言之:

成员包括私有成员和公有成员。

成员分为成员变量和成员函数。

<!--构造函数-->

class Point{

private:

double x;

double y;

public:

Point(){

}

Point(double m, double n) {

x = m; y = n;

}

setPoint(double m, double n){

x = m; y = n;

}

printPoint(){

cout << "(" << x << "," << y << ")" << endl;

}

};

仍然是那个类,多了两个比较怪异的函数。没错,函数的名称和类名称一样,并且他们不含返回值。

有了它们,我们便可以在主函数中这样子声明p。

int main()

{

Point p(3.2, 8.9);

p.printPoint();

return 0;

}

构造函数是在初始化实例的过程中调用的,这样我们可以在初始化的同时给成员赋值,而setPoint用来改变成员的值。

为什么Point函数声明了两次?还记得函数重载么?我们重载了它。

这样我们既可以在声明实例的时候初始化它,也可以不这么做。

因为构造函数总是会执行的。Point p;和Point p();丝毫没有区别。

<!--些许复杂的示例程序-->

#include <iostream>

#include <cstring>

using namespace std;

struct Friend{

char name[20];

Friend* nest;

Friend(char* pn){

strcpy(name, pn);

nest = NULL;

}

};

struct FriendList{

Friend* head;

Friend* mov;

int number;

bool none;

FriendList(Friend* pri){

head = mov = pri;

number = 1;

none = 0;

}

void ReTop(){

mov = head;

none = 0;

}

void BeFriend(Friend* someone){

Friend* temp = mov->nest;

mov->nest = someone;

someone->nest = temp;

number++;

}

bool Que(Friend *f){

if(none) {

cout << "You got no friends.\n\n";

ReTop();

return 0;

}

if(!mov->nest) none = 1;

char ch;

while(getchar() != ‘\n‘) continue;

cout << "Do you wang to make friends with "

<< mov->name << "?" << endl

<< "Y to YES and N to NO" << endl;

cin >> ch;

if(ch == ‘Y‘) {

cout << "You‘ve been friend with " << mov->name << "!\n\n";

BeFriend(f);

ReTop();

return 0;

}else{

mov = mov->nest;

return 1;

}

}

void End()

{

Friend* temp;

while(number--) {

temp = head->nest;

delete(head);

head = temp;

}

}

};

int main()

{

char name[20] = "Always Laugh";

Friend *Me = new Friend(name);

FriendList myFriend(Me);

int T = 4;

while(T--) {

cout << "Enter your name: ";

cin >> name;

Friend* you = new Friend(name);

cout << "Hello " << you->name << "!" << endl;

while(myFriend.Que(you));

}

return 0;

}

这个示例程序对刚接触C++的人来说难度很大,接近一个课设。因为类的内部联系复杂。

并且还用到了动态内存分配(比如new和delete操作符),和链表的内容(这些内容对大家来说是陌生的)。

这是一个交朋友的程序,大家不妨编译运行一下,看看效果,再尽力把代码搞懂(为了避免越界访问,请不要输入得太古怪)。

时间: 2024-08-29 14:22:21

C到C++ 快速过度 C 结构体到类的相关文章

C++中结构体和类的区别

在C++中,结构体是一种特殊形态的类. 结构体和类的唯一区别就是:  结构体和类具有不同的默认访问控制属性. 类中,对于未指定访问控制属性的成员,其访问控制属性为私有类型(private) 结构体中,对于未指定任何访问控制属性的成员,其访问控制属性为公有类型(public) C++中,不使用结构体丝毫不会影响程序的表达能力.C++之所以要引入结构体,是为了保持和C程序的兼容性. 但有时仍会在C++中使用结构体,是因为,可以使用结构体将不同类型数据组成整体,方便于保存数据.(若用类来保存,因类中成

结构体和类的唯一区别就是类函数没有加说明是私有而结构体函数是公有

结构体和类的唯一区别就是              类函数没有加说明是私有                   而   结构体函数是公有

Swift结构体与类

在面向过程的编程语言(如C语言)中,结构体用得比较多,但是面向对象之后,如在C++和Objective-C中,结构体已经很少使用了.这是因为结构体能够做的事情,类完全可以取而代之.而Swift语言却非常重视结构体,把结构体作为实现面向对象的重要手段.Swift中的结构体与C++和Objective-C中的结构体有很大的差别,C++和Objective-C中的结构体只能定义一组相关的成员变量,而Swift中的结构体不仅可以定义成员变量(属性),还可以定义成员方法.因此,我们可以把结构体看做是一种轻

介绍C#结构体与类区别

1. 结构体与类定义方式 结构体定义使用struct类定义使用class 结构体: struct testDemo{ int num; void action(){ } } 类: class testDemo{ int num; void action(){ } } ================== 2. 结构体与类的成员初始化 结构体成员变量在声明时不能赋值,而类在声明变量时会自动写入构造函数完成赋值(即只能定义,不能执行). 结构体中隐式构造函数存在,不能手动写,其余构造函数在手动编写中

[转]C#中的结构体与类的区别

C#中的结构体与类的区别 经常听到有朋友在讨论C#中的结构与类有什么区别.正好这几日闲来无事,自己总结一下,希望大家指点. 1. 首先是语法定义上的区别啦,这个就不用多说了.定义类使用关键字class 定义结构使用关键字struct.在语法上其实类和结构有着很多相似的地方. 定义类的语法 1 class Person 2 { 3 private string name; 4 private int age; 5 6 public void SayHi() 7 { 8 Console.WriteL

Runtime的初步认识——结构体与类

Runtime的初步认识 Runtime的初步认识 Runtime介绍 类与结构体的关系 结构体解析 结构体的作用 Runtime介绍 学习一个东西至少要先知道它是个啥,你一定听说过"运行时是 Objective-C 的一个特色",这里的"运行时"就是指 runtime 了. runtime是在自 iOS 平台开放并基于 Objective-C 语言开发后的一个编程语言上的高级技术. 学习runtime的目的并不是为了开发,而是让你更好的理解 Objective-C

结构体与类

最近开始想学习下Swift,下了Swift3.0中文版PDF,间断性看了几天,发现看不进去,所以还是从实践上学习吧,直接创建工程搭代码,多问度娘. 在此记录下对结构体与类的理解,之前学OC很少碰自定义结构体,所以理解上比较模糊混淆.好吧,我不是个合格的初级开发者. 结构体与类很相似,如初始化和属性访问,定义语法区别关键字struct和class. 在日常开发中,Swift在两者选择上建议第一选择是结构体 p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font:

C++结构体 和类

1 #include <iostream> 2 using namespace std; 3 4 struct father 5 { 6 /* 7 virtual bool set() = 0; 8 virtual bool get() = 0; 9 */ 10 11 virtual bool set(int a, int b) = 0; 12 virtual bool get(int a, int *b) = 0; 13 14 }; 15 struct jack :public father

仿函数--创建结构体或类的内部函数指针

body { font-family: 微软雅黑,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-serif,宋体, PMingLiU,serif; font-size: 10.5pt; line-height: 1.5; } html, body { } h1 { font-size:1.5em; font-weight:bold; } h2 { font-size:1.4em; font-weight:bold; } h3 { fon