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;
}
03-13 23:40