第3章 感受(一)——3.8. Hello object 成员版

白话C++


3.8. Hello object 成员版

前例中,我们定义了一个“不知道是什么东西的”Object类型。一开始,它是一个空空的类型:

struct Object
{

};

而后,我们为它加入了自定义的构造与析构函数。

struct Object
{

Object()
{

std::cout << "Hello world!" << endl;
}

~
Object()
{

std::cout << "Bye-bye world!" << endl;
}
};

于是,这个类型的对象拥有自定义的“生”与“死”的过程,然而,光光讨论对象的“生”与“死”,未免太形而上,太哲学,我们要考虑如何从“抽象”过渡到“具体”。

读者有没有玩过电脑游戏?游戏里面有“魔兽”,“魔兽”通常有以下特点:

第一、 内部通常有“血气值”。

第二、 对外通常有“攻击”能力。

第三、 内部的“血气值”和对外“攻击”能力有一点关联。

有关游戏软件的设计,我们就谈这一些。因为这一些已经够了。这三点说出C++所有“对象”共有的特点。不仅仅是C++程序,现实生活中的“对象”也如此。

〖重要〗:“对象”在表达什么?

第一、对象拥有属性

第二、对象拥有能力

第三、对象的属性改变,往往影响其能力。

想一想“汽车”吧。汽车内部有“油”。汽车的外在能力是:“会跑”。但是,汽车如果油用光了,它就不会跑了。

我们把对象拥有的特征,称为“成员数据”、把它拥有的能力,称为“成员函数”。

人 是最复杂的“对象”之一。因为人有很多“成员数据”,比如:“饥饿度”、“情绪值”、“健康度”;人的能力就更多了,比如“吃喝拉撒”——似乎都算不上什 么本事,再如:“诗书琴画”什么的——似乎现代人有些困难,再往下说,似乎又要开始哲学了,因为人肯定会“死”,可惜析构函数在上节课就说过了。

在 程序中,当我们真的要用一种“类型”来表达“人类”的话,肯定不会费心地把一个人的所有生物的、社会的属性与能力都在代码中做一个映射。我们总中仅仅针对 当前程序所要处理的需求,截取“人”在某一特定方面的数据与能力,,然后用C++类型设计中的“成员数据”与“成员函数”来表达。

本小节中,我们就准备有用“人”来写例子代码。我将根据课程的需要来选择使用“人类”哪些属性与能力。我想没有哪个人类学家会对我有意见。

请在Code::Blocks中创建一个控制台应用项目,取名为:“HelloOOMember”。如有需要,请打开向导自动创建的main.cpp文件,并将其文件编码修改为“系统默认”。

先来一个空的“人”类

struct Person
{

};

然后添加人类的“生死”函数:

struct Person
{

Person()
{

cout << "Wa~Wa~" << endl;
}

~
Person()
{

cout << "Wu~Wu~" << endl;
}
};

3.8.1. 成员数据

进入本节重点,我们为Person添加第一个成员数据:姓名。为了不浪费篇幅,我在下面示例代码中,删除一些前面已经出现的内容,但又为了让大家看起来比较有“感觉”,我将被删除的内容,换成一些文字说明。

struct Person
{

//此处略去:构造与析构函数

string name;
};

新添加的成员数据,类型为“string”,变量名为“name”。为了能正确编译string类型,请自行在main.cpp第002行处添加:

#include <string>

来看看如何使用这个成员数据。

021 int main() 
{

023
Person xiaoA;
024
xiaoA.name = "Xiao A";

026
Person *xiaoB = new Person;
027
(*xiaoB).name = "Xiao B";
028 delete xiaoB;

029 return 0;
}

程序中,我们定义了两个Person的对象。其中xiaoA是“栈对象”,xiaoB是“堆对象”。

024 行演示了如何访问对象的“成员数据”。

024 xiaoA.name = "Xiao A";

这一行将“=”右边的值,赋给“=”左边的对象。

通过对象访问其某一成员数据,语法很简单:

对象.成员数据

不过第027行看上去有些不同:

027 (*xiaoB).name = "Xiao B";

那 是因为xiaoB是堆对象。而堆对象的“真身”其实是“ *xiaoB ”。因此对于栈对象,写的是 xiaoA.name;对于堆对象,写的就本该是 *xiaoB.name了。那又为什么需要一对圆括号呢?这里的括号的作用类似: (1+2)*3 中括号,用来改变运行符的优先级别。在C++中,“星”操作符的优先级比“点”低,因此*xiaoB.name 相当于 *(xiaoB.name),这不是我们想要的,我们要的是:(*xiaoB).name。

这样写实在有些绕,所以C++提供了“->”操作给堆对象使用,所以,027行更常见的写法是:

 xiaoB->name = "Xiao B";

下面,我们除了把027行改成通俗写法以外,还在后面加上用于显示两个对象的name成员的代码。

int main()
{

Person xiaoA;
xiaoA.name = "Xiao A";

Person *xiaoB = new Person;
027
xiaoB->name = "Xiao B";

029 cout << xiaoA.name << endl;
030
cout << xiaoB->name << endl;

032
delete xiaoB;

return
0;
}

请编译并运行以上代码,以下运行结果:

(图 25 成员数据访问)

〖课堂作业〗:复习关键字delete

请大家考虑,上述代码中,030行与032行代码位置,可以对调吗?必须实际动手,将这两行代码对换位置,然后编译并运行。看看结果是什么。

 

3.8.2. 成员函数

我们为Person增加的第一个成员函数,或者说是它第一个能力是:自我介绍。

struct Person
{

//此处省略:构造函数和析构函数

018 void Introduction()
019 {
020
cout << "Hi, my name is " << name << "." << endl;
021
}

std::string name;
};

〖小提示〗:成员数据与函数的位置

把构造与析构函数放在类型定义中最前面,其它成员函数放在中间,成员数据放最后面,这是当今C++界比较流行的风格噢。

 

018到021行定义了一个成员函数。和构造或析构函数不同,成员函数必须指定其返回值类型,本例中,“自我介绍”这一行为不需要返回,所以定为“void”。

有了Introduction函数,它可以替换main函数中原有输出。

int main()
{

Person xiaoA;
xiaoA.name = "Xiao A";

Person *xiaoB = new Person;
xiaoB->name = "Xiao B";

034
xiaoA.Introduction();
035
xiaoB->Introduction();

delete
xiaoB;

return
0;
}

034和035行被替换了,并且我们也看到了,访问和成员函数访问数据在语法并无差别,同样区分“栈对象”和“堆对象”。

请编译、并运行本例程序。


白话C++
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南郁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值