在C ++中,有没有办法区分基类指针所指向的实例类?

时间:2017-05-17 06:53:23

标签: c++ oop

假设有一个Base类和A,B类派生自Base类。

然后,我能找到基类指针所指向的真实实例类吗?

2 个答案:

答案 0 :(得分:2)

我认为RTTI是您正在寻找的答案。 typeiddynamic_cast是您的朋友。

答案 1 :(得分:2)

从实现角度来看,您可以使用dynamic_cast并检查此强制转换是否返回NULL

从形成软件设计的角度来看,我认为在大多数情况下,在运行时请求类型信息的需求表明存在设计问题。可以使用类型信息来确定特定行为是否可用。但通常单个类并不直接反映行为的存在,特别是如果我们认为类层次结构是可扩展的。通常,人们可以通过简单的方式来解决这个问题。特定行为存在或有意义的对象;人们也可以调用行为并信任有意义的默认行为。

让我们来看看#34;炒鸡蛋问题"。考虑到我们有动物养殖场,我们想检查农民是否可以在早餐时吃炒鸡蛋。我们可能会根据动物的运行时类型检查其中一只动物是否为鸡:

class Animal;
class Chicken;
class Cow;

class Farm {
public:
    Farm(initializer_list<Animal*> animals) : ownAnimals(animals) {};
    bool farmerMightHaveScrambledEggs();
private:
    vector<Animal*> ownAnimals;
};

bool Farm::farmerMightHaveScrambledEggs() {
    for (Animal* f : ownAnimals) {
        if (dynamic_cast<Chicken*>(f))
            return true;
    }
    return false;
};

这很有效;但是一旦我们发现不是每只鸡都会产卵,如果我们认为鸵鸟(不是鸡肉)提供用于炒鸡蛋的鸡蛋,这个代码就会失败。这需要调整代码,如果我们只做基于类的检查,可能只需要为了决定scrambled-eggs主题而引入类。和类似#34; EggLayingBirds&#34;甚至&#34; BirdsLayingEggsForScrambledEggs&#34;在类型的水平上听起来非常人为。

因此,更好的方法可能是表达语义,并为炒鸡蛋提供鸡蛋和#34;使用反映此行为的成员函数。

class Animal {
public:
    // the very most animals do not provide eggs one might use for scrambled eggs:
    virtual bool providesEggsForScrambledEggs() { return false; }
};

class Cow : public Animal {
};

class Chicken : public Animal {
    virtual bool providesEggsForScrambledEggs() { return true; }
};

class Ostrich : public Animal {
    virtual bool providesEggsForScrambledEggs() { return true; }
};

bool Farm::farmerMightHaveScrambledEggs_behaviourBased() {
    for (Animal* f : ownAnimals) {
        if (f->providesEggsForScrambledEggs())
            return true;
    }
    return false;
};


bool Farm::farmerMightHaveScrambledEggs_classBased() {
    for (Animal* f : ownAnimals) {
        if (dynamic_cast<Chicken*>(f))
            return true;
    }
    return false;
};

void checkFarmForScrabmledEggs(Farm &f) {
    cout << "farmer might have scrambled eggs: " << f.farmerMightHaveScrambledEggs_behaviourBased() << endl;
    cout << "farmer might have scrambled eggs: " << f.farmerMightHaveScrambledEggs_classBased() << endl;
}

int main(int argc, char* argv[]) {

    Chicken aChicken;
    Cow aCow;

    Farm farmWithChicken ( { &aChicken, &aCow } ); // some eggs
    Farm farmWithCowOnly( { &aCow } ); // no  eggs

    Ostrich anOstrich;
    Farm australianFarm( { &anOstrich } ); // special eggs

    checkFarmForScrabmledEggs(farmWithChicken); // both checks OK
    checkFarmForScrabmledEggs(farmWithCowOnly); // both checks OK
    checkFarmForScrabmledEggs(australianFarm); // class based check fails.

    return 0;
}

可以通过在类层次结构中的特定位置引入数据成员来进一步优化代码,例如,bool providesEggsForScrambledEggs;以更加独立于类层次结构。但这些事情留待读者阅读: - )

希望它有所帮助。