从超类指针复制对象

时间:2011-04-30 01:34:39

标签: c++

假设我有两个类,一个基类和一个继承的类,如下所示:

class Magic : public Attack
{
public:
    Magic(int uID, std::string &name) : Attack(ActionType::MagicAction, uID, name)
    {

    }
};

class MacroMagic : public Magic
{
    MacroMagic(int uID) : Magic(uID, std::string("Testing"))
    {
    }
    void PreUse() override
    {
        std::cout << "Test" << std::endl;
    }
}

我有一个我要复制的魔法实例的shared_ptr,但是在运行时我不知道该指针是指向Magic,MacroMagic还是可能从Magic继承的任何实例。我希望能够复制shared_ptr指向的对象,如下所示:

Battles::magic_ptr mgPtr = MagicNameMap[name];
            if (mgPtr.get() != nullptr)
            {
                return magic_ptr(new Magic(*mgPtr));
            }
            return mgPtr;

其中magic_ptr是Magic Class周围的shared_ptr的typedef。我可以通过指定一个虚拟拷贝函数并调用它来实现它,但我想使它不那么钝,更容易维护。我假设我可以通过复制构造函数执行此操作,但我不确定如何在此实例中。我现在的方式,上面代码返回的指针不会调用覆盖pReUse()函数。

非常感谢一点指导,谢谢

1 个答案:

答案 0 :(得分:1)

  

我可以通过指定虚拟副本函数并调用它来实现它,但我希望减少它的钝化和维护。

你正在反对这种语言。

你可以完成你所追求的目标,但我不推荐它,而且设置或维护肯定不比virtual Magic* clone() = 0更容易。

也许你可以勾勒出能够得出这个结论的问题,然后我们可以从那里得到帮助。通常有替代方案不会与语言作斗争。

修改

这是使用外部函数表(t_magic_operation_table)的方法。你可以应用并创建几个函数表并保持它们。因为它们作为单个指针存在于魔术对象中,所以您可以使这些表格非常大(如果需要)。如果你的魔法类型可以使用相同的数据/成员,那么这是一种方法。小心:我把它扔得太快了。它演示了这种技术,但是它非常糟糕:

#include <iostream>
#include <string>

namespace MONSpiel {

inline unsigned prndm(const unsigned& max) {
    return 1 + arc4random() % max;
}

class t_ghoul;
class t_biclops;

class t_magic;

class t_hero {
    t_hero();
    t_hero(const t_hero&);
    t_hero& operator=(const t_hero&);
public:
    t_hero(const std::string& inName) : d_name(inName) {
    }

    const std::string& name() const {
        return this->d_name;
    }

    template<typename TEnemy, typename TMagic>
    void attack(TEnemy& enemy, TMagic& magic) const {
        if (enemy.isDead()) {
            return;
        }

        enemy.hit(magic.power());

        if (enemy.isDead()) {
            std::cout << this->name() << ": see you in the prequel...\n\n";
        }
        else {
            std::cout << this->name() << ": have you had enough " << magic.name() << ", " << enemy.name() << "???\n\n";
        }
    }

    /* ... */
private:
    const std::string d_name;
};

class t_enemy {
    t_enemy();
    t_enemy(const t_enemy&);
    t_enemy& operator=(const t_enemy&);
public:
    t_enemy(const std::string& inName) : d_name(inName), d_lifePoints(1000) {
    }

    virtual ~t_enemy() {
    }

    const std::string& name() const {
        return this->d_name;
    }

    bool isDead() const {
        return 0 >= this->d_lifePoints;
    }

    const int& lifePoints() const {
        return this->d_lifePoints;
    }

    void hit(const int& points) {
        this->d_lifePoints -= points;
    }

    /* ... */
private:
    const std::string d_name;
    int d_lifePoints;
};

class t_ghoul : public t_enemy {
public:
    static int MaxDaysAwake() {
        return 100;
    }

    t_ghoul(const std::string& inName) : t_enemy(inName), d_bouyancy(prndm(100)), d_proximityToZebra(prndm(100)), d_daysAwake(prndm(MaxDaysAwake())) {
    }

    const int& bouyancy() const {
        return this->d_bouyancy;
    }

    const int& proximityToZebra() const {
        return this->d_proximityToZebra;
    }

    const int& daysAwake() const {
        return this->d_daysAwake;
    }

private:
    int d_bouyancy;
    int d_proximityToZebra;
    int d_daysAwake;
};

class t_biclops : public t_enemy {
public:
    t_biclops(const std::string& inName) : t_enemy(inName), d_isTethered(prndm(2)), d_amountOfSunblockApplied(prndm(100)) {
    }

    const bool& isTethered() const {
        return this->d_isTethered;
    }

    const int& amountOfSunblockApplied() const {
        return this->d_amountOfSunblockApplied;
    }

private:
    bool d_isTethered;
    int d_amountOfSunblockApplied;
};

class t_magic_operation_table {
public:
    typedef void (*t_ghoul_skirmish_function)(t_magic&, t_ghoul&);
    typedef void (*t_biclops_skirmish_function)(t_magic&, t_biclops&);

    t_magic_operation_table(t_ghoul_skirmish_function ghoulAttack, t_biclops_skirmish_function biclopsAttack) : d_ghoulAttack(ghoulAttack), d_biclopsAttack(biclopsAttack) {
    }

    void willSkirmish(t_magic& magic, t_ghoul& ghoul) const {
        this->d_ghoulAttack(magic, ghoul);
    }

    void willSkirmish(t_magic& magic, t_biclops& biclops) const {
        this->d_biclopsAttack(magic, biclops);
    }

private:
    t_ghoul_skirmish_function d_ghoulAttack;
    t_biclops_skirmish_function d_biclopsAttack;
};

class t_action {
public:
    typedef enum t_type {
        NoAction = 0,
        MagicAction,
        ClubAction,
        ClassAction
    } t_type;
};

class t_attack {
public:
    t_attack(const t_action::t_type& actionType, const int& uID, const std::string& inName) : d_actionType(actionType), d_uID(uID), d_name(inName) {
    }

    virtual ~t_attack() {
    }

    void reset() {
        /* ... */
    }

    const std::string& name() const {
        return this->d_name;
    }

private:
    t_action::t_type d_actionType;
    int d_uID;
    std::string d_name;
};

class t_magic : public t_attack {
    t_magic();
    t_magic(const t_magic&);
    t_magic& operator=(const t_magic&);

    static void GhoulSkirmishA(t_magic& magic, t_ghoul& ghoul) {
        magic.d_accuracy = ghoul.bouyancy() + prndm(16);
        magic.d_power = ghoul.proximityToZebra() + prndm(43);
    }

    static void GhoulSkirmishB(t_magic& magic, t_ghoul& ghoul) {
        magic.d_accuracy = ghoul.bouyancy() / magic.flammability() + prndm(32);
        magic.d_power = t_ghoul::MaxDaysAwake() - ghoul.daysAwake() + prndm(23);
    }

    static void BiclopsSkirmishA(t_magic& magic, t_biclops& biclops) {
        if (biclops.isTethered()) {
            magic.d_accuracy = 90 + prndm(16);
        }
        else {
            magic.d_accuracy = 40 + prndm(11);
        }

        magic.d_power = biclops.amountOfSunblockApplied() + prndm(17);
    }

    static void BiclopsSkirmishB(t_magic& magic, t_biclops& biclops) {
        if (biclops.isTethered()) {
            magic.d_accuracy = 80 + prndm(80);
        }
        else {
            magic.d_accuracy = 50 + prndm(50);
        }

        magic.d_power = 80 + prndm(30);
    }

    const t_magic_operation_table* NextOperationTable() {
        static const t_magic_operation_table tables[4] = {
            t_magic_operation_table(GhoulSkirmishA, BiclopsSkirmishA),
            t_magic_operation_table(GhoulSkirmishB, BiclopsSkirmishB),
            t_magic_operation_table(GhoulSkirmishB, BiclopsSkirmishA),
            t_magic_operation_table(GhoulSkirmishA, BiclopsSkirmishB)
        };

        return & tables[arc4random() % 4];
    }

public:
    t_magic(const int& uID, const std::string& inName) : t_attack(t_action::MagicAction, uID, inName), d_power(-1), d_accuracy(-1), d_operationTable(0) {
    }

    int flammability() const {
        return prndm(73);
    }

    int power() const {
        return this->d_power;
    }

    void reset() {
        t_attack::reset();
        this->d_power = -1;
        this->d_accuracy = -1;
        this->d_operationTable = 0;
    }

private:
    /* assigns this->d_operationTable */
    void updateOperationTableForAttack() {
        this->d_operationTable = NextOperationTable();
    }

public:
    void heroWillAttack(const t_hero& hero, t_ghoul& ghoul) {
        this->updateOperationTableForAttack();
        this->d_operationTable->willSkirmish(*this, ghoul);
        std::cout << hero.name() << " vs. " << ghoul.name() << "(lp:" << ghoul.lifePoints() << ")";
        this->printState();
    }

    void heroWillAttack(const t_hero& hero, t_biclops& biclops) {
        this->updateOperationTableForAttack();
        this->d_operationTable->willSkirmish(*this, biclops);
        std::cout << hero.name() << " vs. " << biclops.name() << "(lp:" << biclops.lifePoints() << ")";
        this->printState();
    }

    void printState() {
        std::cout << ": Magic { Power: " << this->d_power << ", Accuracy: " << this->d_accuracy << ", Operation Table: " << this->d_operationTable << "}\n";
    }

private:
    int d_power;
    int d_accuracy;
    const t_magic_operation_table* d_operationTable;
};

template<typename TEnemy>
void AttackEnemyWithMagic(t_hero& hero, TEnemy& enemy, t_magic& magic) {
    if (!enemy.isDead()) {
        magic.heroWillAttack(hero, enemy);
        hero.attack(enemy, magic);
        magic.reset();
    }
}

inline void PlayIt() {

    t_hero zoe("Zoe");
    t_hero aragosta("Aragosta");

    t_ghoul ghoul0("Al Paca");
    t_ghoul ghoul1("Spud");
    t_ghoul ghoul2("Sleepy");

    t_biclops biclops("Scimpanzè");

    t_magic hemlock(59, "hemlock");
    t_magic babyPowder(91, "baby powder");

    for (size_t idx(0); idx < 1000; ++idx) {
        AttackEnemyWithMagic(zoe, ghoul1, hemlock);
        AttackEnemyWithMagic(aragosta, biclops, babyPowder);
        AttackEnemyWithMagic(zoe, ghoul2, hemlock);
        AttackEnemyWithMagic(aragosta, ghoul0, babyPowder);
    }
}
} /* << MONSpiel */

int main(int argc, char* const argv[]) {
#pragma unused(argc)
#pragma unused(argv)
    MONSpiel::PlayIt();
    return 0;
}

另一个选择是简单地创建商店(例如矢量),每个商店都有不同的魔术类型。然后填充一个向量以指向这些商店中的对象。这样,您可以为每种类型创建一个连续分配,并根据需要随机化和权衡。如果你的魔法物品的大小差异很大,这很有用。