《C++游戏编程入门》第9章 高级类与动态内存:Game Lobby
9.1 使用聚合体
对象的组合,对象成员变量含其他对象。
09.critter_farm.cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Critter
{
public:
Critter(const string &name = "");
string GetName() const;
private:
string m_Name; // 对象包含关系
};
Critter::Critter(const string &name)
: m_Name(name)
{
}
inline string Critter::GetName() const
{
return m_Name;
}
class Farm
{
public:
Farm(int spaces = 1);
void Add(const Critter &aCritter);
void RollCall() const;
private:
vector<Critter> m_Critters;
};
Farm::Farm(int spaces)
{
m_Critters.reserve(spaces);
}
void Farm::Add(const Critter &aCritter)
{
m_Critters.push_back(aCritter);
}
void Farm::RollCall() const
{
for (vector<Critter>::const_iterator iter = m_Critters.begin(); iter != m_Critters.end(); ++iter)
cout << iter->GetName() << " here.\n";
}
int main()
{
Critter crit("Poochie");
cout << "My critter's name is " << crit.GetName() << endl;
cout << "\nCreating critter farm.\n";
Farm myFarm(3);
cout << "\nAdding three critters to the farm.\n";
myFarm.Add(Critter("Moe"));
myFarm.Add(Critter("Larry"));
myFarm.Add(Critter("Curly"));
cout << "\nCalling Roll...\n";
myFarm.RollCall();
return 0;
}
9.2 使用友元函数与运算符重载
友元函数对类的任何成员都有完全的访问权。
09.friend_critter.cpp
#include <iostream>
#include <string>
using namespace std;
class Critter
{
// 友元函数
friend void Peek(const Critter &aCritter);
friend ostream &operator<<(ostream &os, const Critter &aCritter);
public:
Critter(const string &name = "");
private:
string m_Name;
};
Critter::Critter(const string &name)
: m_Name(name)
{
}
void Peek(const Critter &aCritter);
ostream &operator<<(ostream &os, const Critter &aCritter);
int main()
{
Critter crit("Poochie");
cout << "Calling Peek() to access crit's private data member, m_Name: \n";
Peek(crit);
cout << "\nSending crit object to cout with the << operator:\n";
cout << crit;
return 0;
}
void Peek(const Critter &aCritter)
{
cout << aCritter.m_Name << endl;
}
// 运算符重载
ostream &operator<<(ostream &os, const Critter &aCritter)
{
os << "Critter Object - m_Name: " << aCritter.m_Name;
return os;
}
9.3 动态分配内存
堆(自由存储区),程序员负责分配与释放。
09.heap.cpp
#include <iostream>
using namespace std;
int *intOnHeap(); // returns an int on the heap
void leak1(); // creates a memory leak
void leak2(); // creates another memory leak
int main()
{
int *pHeap = new int;//new运算符
*pHeap = 10;
cout << "*pHeap: " << *pHeap << "\n\n";
int *pHeap2 = intOnHeap();
cout << "*pHeap2: " << *pHeap2 << "\n\n";
cout << "Freeing memory pointed to by pHeap.\n\n";
delete pHeap;//显示地释放
cout << "Freeing memory pointed to by pHeap2.\n\n";
delete pHeap2;
// get rid of dangling pointers
pHeap = nullptr;
pHeap2 = 0;
return 0;
}
int *intOnHeap()
{
int *pTemp = new int(20);//分配同时初始化
return pTemp;
}
void leak1()
{
int *drip1 = new int(30);
}
void leak2()
{
int *drip2 = new int(50);
drip2 = new int(100);
delete drip2;
}
9.4 使用数据成员与堆
09.heap_data_member.cpp
#include <iostream>
#include <string>
using namespace std;
class Critter
{
public:
Critter(const string &name = "", int age = 0); // 构造函数
~Critter(); // 析构函数
Critter(const Critter &c); // 拷贝构造函数
Critter &operator=(const Critter &c); // 拷贝赋值运算符
void Greet() const;
private:
string *m_pName;
int m_Age;
};
Critter::Critter(const string &name, int age)
{
cout << "Constructor called\n";
m_pName = new string(name); // 分配堆空间
m_Age = age;
}
Critter::~Critter() // destructor definition
{
cout << "Destructor called\n";
delete m_pName; // 释放堆空间
}
Critter::Critter(const Critter &c) // copy constructor definition
{
cout << "Copy Constructor called\n";
m_pName = new string(*(c.m_pName));
m_Age = c.m_Age;
}
Critter &Critter::operator=(const Critter &c) // overloaded assignment op def
{
cout << "Overloaded Assignment Operator called\n";
if (this != &c)
{
delete m_pName;
m_pName = new string(*(c.m_pName));
m_Age = c.m_Age;
}
return *this;
}
void Critter::Greet() const
{
cout << "I'm " << *m_pName << " and I'm " << m_Age << " years old. ";
cout << "&m_pName: " << &m_pName << endl;
}
void testDestructor();
void testCopyConstructor(Critter aCopy);
void testAssignmentOp();
int main()
{
testDestructor();
cout << endl;
Critter crit("Poochie", 5);
crit.Greet();
testCopyConstructor(crit);
crit.Greet();
cout << endl;
testAssignmentOp();
return 0;
}
void testDestructor()
{
Critter toDestroy("Rover", 3);
toDestroy.Greet();
}
void testCopyConstructor(Critter aCopy)
{
aCopy.Greet();
}
void testAssignmentOp()
{
Critter crit1("crit1", 7);
Critter crit2("crit2", 9);
crit1 = crit2;
crit1.Greet();
crit2.Greet();
cout << endl;
Critter crit3("crit", 11);
crit3 = crit3;
crit3.Greet();
}
9.5 Game Lobby程序
09.game_lobby.cpp
#include <iostream>
#include <string>
using namespace std;
class Player
{
public:
Player(const string &name = "");
string GetName() const;
Player *GetNext() const;
void SetNext(Player *next);
private:
string m_Name;
Player *m_pNext; // Pointer to next player in list
};
Player::Player(const string &name)
: m_Name(name), m_pNext(nullptr)
{
}
string Player::GetName() const
{
return m_Name;
}
Player *Player::GetNext() const
{
return m_pNext;
}
void Player::SetNext(Player *next)
{
m_pNext = next;
}
class Lobby
{
friend ostream &operator<<(ostream &os, const Lobby &aLobby);
public:
Lobby();
~Lobby();
void AddPlayer();
void RemovePlayer();
void Clear();
private:
Player *m_pHead;
};
Lobby::Lobby()
: m_pHead(nullptr)
{
}
Lobby::~Lobby()
{
Clear();
}
void Lobby::AddPlayer()
{
// create a new player node
cout << "Please enter the name of the new player: ";
string name;
cin >> name;
Player *pNewPlayer = new Player(name);
// if list is empty, make head of list this new player
if (m_pHead == nullptr)
{
m_pHead = pNewPlayer;
}
// otherwise find the end of the list and add the player there
else
{
Player *pIter = m_pHead;
while (pIter->GetNext() != nullptr)
pIter = pIter->GetNext();
pIter->SetNext(pNewPlayer);
}
}
void Lobby::RemovePlayer()
{
if (m_pHead == nullptr)
{
cout << "The game lobby is empty. No one to remove!\n";
}
else
{
Player *pTemp = m_pHead;
m_pHead = m_pHead->GetNext();
delete pTemp;
}
}
void Lobby::Clear()
{
while (m_pHead != nullptr)
RemovePlayer();
}
ostream &operator<<(ostream &os, const Lobby &aLobby)
{
Player *pIter = aLobby.m_pHead;
os << "\nHere's who's in the game lobby:\n";
if (pIter == nullptr)
{
os << "The lobby is empty.\n";
}
else
{
while (pIter != nullptr)
{
os << pIter->GetName() << endl;
pIter = pIter->GetNext();
}
}
return os;
}
int main()
{
Lobby myLobby;
int choice;
do
{
cout << myLobby;
cout << "\nGAME LOBBY\n";
cout << "0 - Exit the program.\n";
cout << "1 - Add a player to the lobby.\n";
cout << "2 - Remove a player from the lobby.\n";
cout << "3 - Clear the lobby.\n\n";
cout << "Enter choice: ";
cin >> choice;
switch (choice)
{
case 0:
cout << "Good-bye.\n";
break;
case 1:
myLobby.AddPlayer();
break;
case 2:
myLobby.RemovePlayer();
break;
case 3:
myLobby.Clear();
break;
default:
cout << "That was not a valid choice.\n";
}
} while (choice != 0);
return 0;
}