15-x 第十五章总结与测验(doing)
章节回顾
在每个(非静态)成员函数内部,关键字 this 是一个 const 指针,它保存当前隐式对象的地址。我们可以让函数通过引用返回 *this,从而实现方法链method chaining式调用——即在单个表达式中对同一个对象调用多个成员函数。
建议将类定义放置于与类同名的头文件中。简单成员函数(如访问函数、空主体构造函数等)可直接定义在类体内。
非简单成员函数建议定义在与类同名的源文件中。
在类类型内部定义的类型称为嵌套类型nested type(或成员类型member type)。类型别名也可嵌套定义。
在类模板定义内部定义的成员函数可使用该类模板自身的模板参数。在类模板定义外部定义的成员函数必须重新提供模板参数声明,且应在类模板定义下方(同一文件内)进行定义。
静态成员变量Static member variables是具有静态作用域的成员,由类的所有对象共享。即使未实例化该类对象,静态成员依然存在。建议通过类名、作用域解析运算符及成员名进行访问。
将静态成员声明为inline可使其在类定义内部初始化。
静态成员函数Static member functions是无需对象即可调用的成员函数。它们不拥有*this指针,且无法访问非静态数据成员。
在类主体内部,可使用friend关键字声明友元关系friend declaration,告知编译器某个类或函数已成为该类的友元。友元friend是指被授予完全访问权限的类或函数(成员函数或非成员函数),可访问其他类的私有及受保护成员。友元函数friend function是指能像该类成员函数那样访问私有及受保护成员的函数(成员函数或非成员函数)。友元类friend class是指可访问其他类私有及受保护成员的类。
测验时间
问题 #1
让我们创建一个随机怪物生成器。这个应该很有趣。
a) 首先,创建一个名为 MonsterType 的怪物类型范围枚举。包含以下怪物类型:龙、哥布林、食人魔、兽人、骷髅、巨魔、吸血鬼和僵尸。添加一个额外的 maxMonsterTypes 枚举器,以便统计枚举器的总数。
龙:Dragon, 哥布林:Goblin, 食人魔:Ogre, 兽人:Orc, 骷髅:Skeleton, 巨魔:Troll, 吸血鬼:Vampire, and 僵尸:Zombie.
显示解决方案
enum class MonsterType
{
dragon,
goblin,
ogre,
orc,
skeleton,
troll,
vampire,
zombie,
maxMonsterTypes,
};
b) 接着创建Monster类。怪物将拥有4个属性(成员变量):类型(MonsterType)、名称(std::string)、咆哮声(std::string)和生命值(int)。
显示解决方案
#include <string>
enum class MonsterType
{
dragon,
goblin,
ogre,
orc,
skeleton,
troll,
vampire,
zombie,
maxMonsterTypes,
};
class Monster
{
private:
MonsterType m_type{};
std::string m_name{"???"};
std::string m_roar{"???"};
int m_hitPoints{};
};
c) MonsterType枚举类专属于Monster类,因此将其改为Monster类内的嵌套无作用域枚举,并重命名为Type。
显示解决方案
#include <string>
class Monster
{
public:
enum Type
{
dragon,
goblin,
ogre,
orc,
skeleton,
troll,
vampire,
zombie,
maxMonsterTypes,
};
private:
Type m_type{};
std::string m_name{"???"};
std::string m_roar{"???"};
int m_hitPoints{};
};
d) 创建构造函数以初始化所有成员变量。
以下程序应能编译通过:
int main()
{
Monster skeleton{ Monster::skeleton, "Bones", "*rattle*", 4 };
return 0;
}
显示答案
#include <string>
#include <string_view>
class Monster
{
public:
enum Type
{
dragon,
goblin,
ogre,
orc,
skeleton,
troll,
vampire,
zombie,
maxMonsterTypes,
};
private:
Type m_type{};
std::string m_name{"???"};
std::string m_roar{"???"};
int m_hitPoints{};
public:
Monster(Type type, std::string_view name, std::string_view roar, int hitPoints)
: m_type{ type }, m_name{ name }, m_roar{ roar }, m_hitPoints{ hitPoints }
{
}
};
int main()
{
Monster skeleton{ Monster::skeleton, "Bones", "*rattle*", 4 };
return 0;
}
e) 现在我们需要能够打印怪物,以便验证其正确性。编写两个函数:一个名为 getTypeString() 的函数,用于返回怪物的类型字符串;另一个名为 print() 的函数,其输出应与下方示例程序中的输出一致。
以下程序应能编译通过:
int main()
{
Monster skeleton{ Monster::skeleton, "Bones", "*rattle*", 4 };
skeleton.print();
Monster vampire{ Monster::vampire, "Nibblez", "*hiss*", 0 };
vampire.print();
return 0;
}
并打印:
Bones the skeleton has 4 hit points and says *rattle*.
Nibblez the vampire is dead.

显示答案
#include <iostream>
#include <string>
#include <string_view>
class Monster
{
public:
enum Type
{
dragon,
goblin,
ogre,
orc,
skeleton,
troll,
vampire,
zombie,
maxMonsterTypes,
};
private:
Type m_type{};
std::string m_name{"???"};
std::string m_roar{"???"};
int m_hitPoints{};
public:
Monster(Type type, std::string_view name, std::string_view roar, int hitPoints)
: m_type{ type }, m_name{ name }, m_roar{ roar }, m_hitPoints{ hitPoints }
{
}
constexpr std::string_view getTypeString() const
{
switch (m_type)
{
case dragon: return "dragon";
case goblin: return "goblin";
case ogre: return "ogre";
case orc: return "orc";
case skeleton: return "skeleton";
case troll: return "troll";
case vampire: return "vampire";
case zombie: return "zombie";
default: return "???";
}
}
void print() const
{
std::cout << m_name << " the " << getTypeString();
if (m_hitPoints <= 0)
std::cout << " is dead.\n";
else
std::cout << " has " << m_hitPoints << " hit points and says " << m_roar << ".\n";
}
};
int main()
{
Monster skeleton{ Monster::skeleton, "Bones", "*rattle*", 4 };
skeleton.print();
Monster vampire{ Monster::vampire, "Nibblez", "*hiss*", 0 };
vampire.print();
return 0;
}
f) 现在我们可以创建一个随机怪物生成器。让我们考虑MonsterGenerator的工作原理。理想情况下,我们会要求它生成一个怪物,它将为我们随机创建一个。由于MonsterGenerator没有状态,它非常适合用作命名空间。
创建 MonsterGenerator 命名空间。在其中创建名为 generate() 的函数,该函数应返回 Monster 类型。当前实现使其返回 Monster{ Monster::skeleton, “Bones”, “rattle”, 4};
以下程序应能编译通过:
int main()
{
Monster m{ MonsterGenerator::generate() };
m.print();
return 0;
}
并打印:
Bones the skeleton has 4 hit points and says *rattle*

显示答案
#include <iostream>
#include <string>
#include <string_view>
class Monster
{
public:
enum Type
{
dragon,
goblin,
ogre,
orc,
skeleton,
troll,
vampire,
zombie,
maxMonsterTypes,
};
private:
Type m_type{};
std::string m_name{};
std::string m_roar{};
int m_hitPoints{};
public:
Monster(Type type, std::string_view name, const std::string& roar, int hitPoints)
: m_type{ type }, m_name{ name }, m_roar{ roar }, m_hitPoints{ hitPoints }
{
}
constexpr std::string_view getTypeString() const
{
switch (m_type)
{
case Type::dragon: return "dragon";
case Type::goblin: return "goblin";
case Type::ogre: return "ogre";
case Type::orc: return "orc";
case Type::skeleton: return "skeleton";
case Type::troll: return "troll";
case Type::vampire: return "vampire";
case Type::zombie: return "zombie";
default: return "???";
}
}
void print() const
{
if (m_hitPoints <= 0)
std::cout << m_name << " is dead.\n";
else
std::cout << m_name << " the " << getTypeString() << " has " << m_hitPoints << " hit points and says " << m_roar << ".\n";
}
};
namespace MonsterGenerator
{
Monster generate()
{
return Monster{ Monster::skeleton, "Bones", "*rattle*", 4 };
}
};
int main()
{
Monster m{ MonsterGenerator::generate() };
m.print();
return 0;
}
g) 在MonsterGenerator命名空间中再添加两个函数。getName(int)函数将接受0到5之间的整数(含边界值),并返回你选择的名称。getRoar(int)函数同样接受0到5之间的整数(含边界值),并返回你选择的吼叫声。同时更新你的generate()函数,使其调用getName(0)和getRoar(0)。
以下程序应能编译通过:
int main()
{
Monster m{ MonsterGenerator::generate() };
m.print();
return 0;
}
并打印:
Blarg the skeleton has 4 hit points and says *ROAR*
你的名称和声音将根据你的选择而变化。
显示答案
#include <iostream>
#include <string>
#include <string_view>
class Monster
{
public:
enum Type
{
dragon,
goblin,
ogre,
orc,
skeleton,
troll,
vampire,
zombie,
maxMonsterTypes,
};
private:
Type m_type{};
std::string m_name{"???"};
std::string m_roar{"???"};
int m_hitPoints{};
public:
Monster(Type type, std::string_view name, std::string_view roar, int hitPoints)
: m_type{ type }, m_name{ name }, m_roar{ roar }, m_hitPoints{ hitPoints }
{
}
constexpr std::string_view getTypeString() const
{
switch (m_type)
{
case dragon: return "dragon";
case goblin: return "goblin";
case ogre: return "ogre";
case orc: return "orc";
case skeleton: return "skeleton";
case troll: return "troll";
case vampire: return "vampire";
case zombie: return "zombie";
default: return "???";
}
}
void print() const
{
std::cout << m_name << " the " << getTypeString();
if (m_hitPoints <= 0)
std::cout << " is dead.\n";
else
std::cout << " has " << m_hitPoints << " hit points and says " << m_roar << ".\n";
}
};
namespace MonsterGenerator
{
std::string_view getName(int n)
{
switch (n)
{
case 0: return "Blarg";
case 1: return "Moog";
case 2: return "Pksh";
case 3: return "Tyrn";
case 4: return "Mort";
case 5: return "Hans";
default: return "???";
}
}
std::string_view getRoar(int n)
{
switch (n)
{
case 0: return "*ROAR*";
case 1: return "*peep*";
case 2: return "*squeal*";
case 3: return "*whine*";
case 4: return "*growl*";
case 5: return "*burp*";
default: return "???";
}
}
Monster generate()
{
return Monster{ Monster::skeleton, getName(0), getRoar(0), 4 };
}
};
int main()
{
Monster m{ MonsterGenerator::generate() };
m.print();
return 0;
}
h) 现在我们将随机生成怪物。从8.15节——全局随机数(Random.h)中获取“Random.h”代码并保存为Random.h。然后使用Random::get()生成随机怪物类型、随机名称、随机吼叫声和随机生命值(范围1至100)。
以下程序应能编译通过:
#include "Random.h"
int main()
{
Monster m{ MonsterGenerator::generate() };
m.print();
return 0;
}
并打印类似以下内容:
Mort the zombie has 61 hit points and says *growl*
显示答案
#include "Random.h"
#include <iostream>
#include <string>
#include <string_view>
class Monster
{
public:
enum Type
{
dragon,
goblin,
ogre,
orc,
skeleton,
troll,
vampire,
zombie,
maxMonsterTypes,
};
private:
Type m_type{};
std::string m_name{"???"};
std::string m_roar{"???"};
int m_hitPoints{};
public:
Monster(Type type, std::string_view name, std::string_view roar, int hitPoints)
: m_type{ type }, m_name{ name }, m_roar{ roar }, m_hitPoints{ hitPoints }
{
}
constexpr std::string_view getTypeString() const
{
switch (m_type)
{
case dragon: return "dragon";
case goblin: return "goblin";
case ogre: return "ogre";
case orc: return "orc";
case skeleton: return "skeleton";
case troll: return "troll";
case vampire: return "vampire";
case zombie: return "zombie";
default: return "???";
}
}
void print() const
{
std::cout << m_name << " the " << getTypeString();
if (m_hitPoints <= 0)
std::cout << " is dead.\n";
else
std::cout << " has " << m_hitPoints << " hit points and says " << m_roar << ".\n";
}
};
namespace MonsterGenerator
{
std::string_view getName(int n)
{
switch (n)
{
case 0: return "Blarg";
case 1: return "Moog";
case 2: return "Pksh";
case 3: return "Tyrn";
case 4: return "Mort";
case 5: return "Hans";
default: return "???";
}
}
std::string_view getRoar(int n)
{
switch (n)
{
case 0: return "*ROAR*";
case 1: return "*peep*";
case 2: return "*squeal*";
case 3: return "*whine*";
case 4: return "*growl*";
case 5: return "*burp*";
default: return "???";
}
}
Monster generate()
{
return Monster{
static_cast<Monster::Type>(Random::get(0, Monster::maxMonsterTypes-1)),
getName(Random::get(0,5)),
getRoar(Random::get(0,5)),
Random::get(1, 100)
};
}
};
int main()
{
Monster m{ MonsterGenerator::generate() };
m.print();
return 0;
}

浙公网安备 33010602011771号