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.

image

显示答案

#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*

image

显示答案

#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;
}
posted @ 2026-01-03 18:29  游翔  阅读(13)  评论(0)    收藏  举报