首页 > 解决方案 > 我应该如何实现现有父对象的临时子对象?

问题描述

我知道这个问题听起来很奇怪,所以让我从这些问题开始:

问题 1

我正在制作一个大富翁游戏(Monopoly已经制作了一个有PlayerList成员的类,包含玩家),并且我已经实现了一个Auction类。最近发现自己的Auctionclass和PlayerListclass里面有很多可比的代码,所以在class里面放了很多Auction-code BidderList

// Auction.cpp
Auction::Auction(Property* property, PlayerList* bidderList, int currBidderIndex)
    : m_property{ property }, m_bidderList{ new BidderList(bidderList, currBidderIndex) },
    m_highestBid{ startBid }, m_previous_has_left{ false }
{
}

// BidderList.cpp
BidderList::BidderList(PlayerList* playerList, int currBidderIndex)
    : PlayerList(playerList)
{
    m_currPlayerIndex = currBidderIndex;
}

但是...在我的拍卖实现中,它被用作临时对象,完成后将被销毁。(是的,我可以给它设置器。)由于我使用的是原始播放器对象(需要修改它们),所以当BidderList对象被破坏时,我也会(无意地)删除基本析构函数中的那些:

PlayerList::~PlayerList()
{
    for (const auto player : m_players)
        delete player;
}

...这迫使我做这样的事情:

// Prevent base class from deleting the players! - not so clean
BidderList::~BidderList()
{
    int size = getSize();
    for (int i = 0; i < size; ++i)
        m_players[i] = nullptr;
}

我仍然想在拍卖后使用我的球员,因为不确定比赛是否会结束。我想知道我是否可以以更清洁的方式做到这一点。

问题 2

我也在考虑从 Player 类中派生Bidder和 ( Traderfor Trade)(这并没有以任何明显的方式解决前面的问题),因为这样我可以再次获得更高的凝聚力。尽管在这种情况下问题不大,但我仍然想知道以下问题的答案:

不知何故,每个玩家都在拍卖期间充当竞标者(这仍然是暂时的)。

如果我设法将实际玩家转换为投标人(所以我将使用原始玩家对象),那么我仍然必须确保只有派生类被销毁 - 对我来说听起来像是虚构的。那么这里使用复合关系就没有其他方法了吗?因为,它看起来像这样,它并不漂亮:

bool Derived::foo()
{
    return m_base.foo();
}

在这两个问题中,我都需要一个临时派生类,由现有的父类构建,之后需要以安全的方式对其进行清理。你能帮我在这里做出正确的决定吗?(是的,我确实想将拍卖对象保留为临时对象,只是为了练习)。提前致谢!

标签: c++inheritancec++17

解决方案


我考虑std::shared_ptr<Object>了一段时间,我想我已经找到了第二个问题的解决方案,尽管它仍然有一点缺点,即每个需要在子类中修改的成员都必须是 a shared_ptr,即使你不会不要让它成为一个指针。请参阅下面的代码,代表假期员工的课程。

/* - - - - - - - HEADER- - - - - - - -*/
#pragma once
#include <string>
#include <memory>

class Person
{
public:
    Person(std::string name, int capital = 1000);
    std::string getName() const;
    virtual void print() const = 0;
protected:
    std::string m_name;
    std::shared_ptr<int> m_capital;
};

/* - - - - - - - SOURCE- - - - - - - -*/
#include "Person.h"

#include <iostream>

Person::Person(std::string name, int capital)
    : m_name{ name }, m_capital{ std::shared_ptr<int>(new int{capital}) }
{
}

std::string Person::getName() const
{
    return m_name;
}

员工

/* - - - - - - - HEADER- - - - - - - -*/
#pragma once
#include "Person.h"

class Employee : public Person
{
public:
    Employee(std::string name, std::string workName);
    std::string getWorkName() const;
    void print() const override;
private:
    std::string m_workName;
};

/* - - - - - - - SOURCE- - - - - - - -*/
#include "Employee.h"

#include <iostream>

Employee::Employee(std::string name, std::string workName)
    : Person(name), m_workName{ workName }
{
}

std::string Employee::getWorkName() const
{
    return m_workName;
}

void Employee::print() const
{
    std::cout
        << m_name << '\n'
        << "  I'm an employee at " << m_workName << '\n'
        << "  I have a capital of " << std::to_string(*m_capital) << '\n'
        ;
}

游客

/* - - - - - - - HEADER- - - - - - - -*/
#pragma once
#include "Person.h"
#include <queue>

class Tourist : public Person
{
public:
    Tourist(std::string name, std::queue<std::string> destinations);
    Tourist(const Person& person, std::queue<std::string> destinations);
    void visitNextDestination();
    void print() const override;
private:
    std::queue<std::string> m_destinations;
};

/* - - - - - - - SOURCE- - - - - - - -*/
#include "Tourist.h"

#include <iostream>

Tourist::Tourist(std::string name, std::queue<std::string> destinations)
    : Person(name), m_destinations{destinations}
{
}

Tourist::Tourist(const Person& person, std::queue<std::string> destinations)
    : Person(person), m_destinations{destinations}
{
}

void Tourist::visitNextDestination()
{
    if (m_destinations.size() > 0) {
        m_destinations.pop();
        *m_capital -= 100;
    }
}

void Tourist::print() const
{
    std::cout
        << m_name << '\n'
        << "  I'm a tourist heading for " << m_destinations.front() << '\n'
        << "  I have a capital of " << std::to_string(*m_capital) << '\n'
        ;
}

主文件

#include "Employee.h"
#include "Tourist.h"

int main()
{
    std::queue<std::string> destinations;
    destinations.push("Paris");
    destinations.push("London");
    destinations.push("Berlin");

    std::vector<Person*> persons{
        new Employee{"Harry", "Microsoft"},
        new Employee{"Frank", "Apple"},
        new Tourist{"Bob", destinations}
    };

    for (const auto person : persons)
        person->print();

    Tourist* frank = new Tourist{ *persons[1], destinations };
    frank->visitNextDestination();
    frank->print();

    delete frank;
    persons[1]->print();
}

输出

Harry
  I'm an employee at Microsoft
  I have a capital of 1000
Frank
  I'm an employee at Apple
  I have a capital of 1000
Bob
  I'm a tourist heading for Paris
  I have a capital of 1000
Frank
  I'm a tourist heading for London
  I have a capital of 900
Frank
  I'm an employee at Apple
  I have a capital of 900

推荐阅读