0

以下に説明するクラスを取得しました

class Investment
{
private:
    void init(BWAPI::UnitType type1, BWAPI::UpgradeType type2, BWAPI::TechType type3, int numOfItems);
    UpgradeType upgradeType;
    TechType techType;
    UnitType unitType;

私のinitメソッドはそのようなものです

void Investment::init(BWAPI::UnitType type1, BWAPI::UpgradeType type2, BWAPI::TechType type3, int numOfItems)
{
    if (type1 != NULL) {

        this->unitType = type1;
        this->type = type1.isBuilding() ? BUILDING_TYPE : UNIT_TYPE;

    } else if (type2 != NULL) {

        this->upgradeType = type2;  
        this->type = UPGRADE_TYPE;

    } else if (type3 != NULL) {

        this->techType = type3; 
        this->type = TECH_TYPE;
    }

    this->numOfItems = numOfItems;
}

この方法でアイテムを取得します (3 つの可能なタイプのうちの 1 つにすぎません)。

const void* Investment::getItem() const
{
    if (unitType != NULL)
        return &unitType;
    else if (upgradeType != NULL)
        return &upgradeType;
    else if (techType != NULL)
        return &techType;

    return NULL;
}

しかし、ポインターを使用してアイテムを取得するとどうなるか、UnitType* type = (UnitType*) investment->getItem();その値を失います

呼び出すtype->getName().c_str();と、空の文字列が返されます

投資を得るために Stack のメソッドを呼び出します

// I have a stack of type std::vector<T*> stack;

T* getNext() {

    clear();

    for (int i = 0, leni = stack.size(); i < leni; i++) {

        T* t = stack.at(i);

        if (!t->isDone() && !t->isCanceled())
            return t;
    }

    return NULL;
}
4

3 に答える 3

2

クラスに基本クラスへのInvestment(できればsmart)ポインターを保持させることで、問題を大幅に簡素化できると思います。Typeこの例では、デストラクタで削除される生のポインタを使用していますが、タイプの有効期間をデストラクタから切り離したい場合はInvestment、おそらくstd::unique_ptrboost::scoped_ptr、またはstd::shared_ptrInvestmentを使用する必要があります。 .

class InvestmentType { // some public virtual methods };

class UpdgadeType : public InvestmentType { /* Implement InvestmentType methods*/ };
class TechType : public InvestmentType { /* Implement InvestmentType methods*/ };
class UnitType : public InvestmentType { /* Implement InvestmentType methods*/ };

class Investment
{
 private:
    void init(const InvestmentType&  type, int numOfItems) : nItems_(numOfItems), type_(new type) {}
    int nItems_;
    InvestmentType* type_;
    ~Investment() { delete type_; }
 public:
    const InvestmentType* getItem() const { return type_; }
};
于 2012-12-11T07:17:56.057 に答える
1

コードをざっと見ただけで疑わしくなります... 使用されている型 (つまりUpgradeTypeTechTypeおよびUnitType) はポインターですか? address-of 演算子を使用してポインタを に返しているため、そのようには見えませんgetItem

それらがポインターでないNULL場合、非ポインターは決して ではないため、それらを と比較することはできませんNULL。これは、常に変数へのポインターを返すことgetItemを意味します。unitType

juanchopanza の回答で提案されているように、再設計を行うことをお勧めします。

于 2012-12-11T08:52:16.347 に答える
0

提案どおりにリファクタリングできないためtype、関数で割り当てるメンバーに基づいて、どの型を返す必要があるかを確認する必要がありinit()ます。これはうまくいくと思いますが、typeが定義されている場所を示していません:

const void* Investment::getItem() const
{
    switch(type)
    {
        case BUILDING_TYPE:
        case UNIT_TYPE:
           return &unitType;
        case UPGRADE_TYPE:
           return &upgradeType;
        case TECH_TYPE:
           return &techType;
    }

    return NULL;
}

ただし、これを行うと、の呼び出し元がgetItem()適切なダウンキャストを実行できる必要があります。これを明示的に提供しないと、コードのユーザーが常に混乱する原因になります。

でも:

クラスのユーザーが正しい型にダウンキャストされることを期待している場合void*、これはほとんどの場合、 の設計が悪いことを示していC++ます。正しいアプローチは、@juanchopanza の回答で提案されているように、これを適切なポリモーフィック クラス階層にリファクタリングすることです。

于 2012-12-11T19:19:37.370 に答える