Pergunta

We are supposed to make classes of animals which inherit from classes of different types of animals, i.e the Dog class will inherit from the Carnivore class which will inherit from the Mammal class. I have tried using my classes in my own main function and they print out what they are supposed to say and their name but when I run my classes with my teacher's main file it tells me its dumping stack trace.

#include <iostream>
#include <string>
#include <typeinfo>
#include <vector>

using namespace std;

class Mammal {
public:
    virtual string say() = 0;
    virtual string name() = 0;
};

class Carnivore : public Mammal {
public:
    virtual string say() = 0;
    virtual string name() = 0;
};

class Canid : public Carnivore{
public:
    virtual string say() = 0;
    virtual string name() = 0;
};

class Dog : public Canid{
public:
    string say(){
        return "bark";
    }
    string name(){
        return "dog";
    }
};

class Fox : public Canid{
public:
    Fox(){
        spoke = "ay";
    }
    std::string say(){
        spoke += spoke;
        return spoke;
    }
    std::string name(){
        return "fox";
    }
private:
    std::string spoke;
};

class Feline : public Canid{
public: 
    virtual string say() = 0;
    virtual string name() = 0;
 };

class Cat : public Feline{
public:
    std::string say(){
        return "moew";
    }
    std::string name(){
        return "cat";
    }
};

class Rodent : public Mammal{
public: 
    virtual string say() = 0;
    virtual string name() = 0;
};

class Mouse : public Rodent{
public:
    std::string say(){
        return "squeak";
    }
    std::string name(){
        return "mouse";
    }
};

Mammal* MammalFactory(const std::type_info& ti){

    if(ti == typeid(Dog)){
        cout << "running dog" << endl;
        Dog D;
        Mammal* dog = &D;
        return dog;
    }
    else if (ti == typeid(Fox)){
        cout << "running fox" << endl;
        Fox F;
        Mammal* fox = &F;
        return fox;
    }
    else if (ti == typeid(Cat)){
        cout << "running cat" << endl;
        Cat C;
        Mammal* cat = &C;
        return cat;
    }
    else if (ti == typeid(Mouse)){
        cout << "running mouse" << endl;
        Mouse M;
        Mammal* mouse = &M;
        return mouse;
    }
    else{
        return NULL;
    }
}

int main(){

    int score = 90;
    std::vector<Mammal*> mammals;
    mammals.push_back(MammalFactory(typeid(Dog)));
    mammals.push_back(MammalFactory(typeid(Cat)));
    mammals.push_back(MammalFactory(typeid(Mouse)));
    Mammal* fox = MammalFactory(typeid(Fox));

    mammals.at(0)->name();

    for (std::vector<Mammal*>::iterator I = mammals.begin(); I != mammals.end(); ++I) {
        std::cout<<(*I)->name()<<" goes "<<(*I)->say()<<'\n';
    }

    //Check animal names
    if (mammals.at(0)->name() != "dog") {
        std::cout<<"Dog's name is incorrect! -10\n";
        score -= 10;
    }
    if (mammals.at(1)->name() != "cat") {
        std::cout<<"Cat's name is incorrect! -10\n";
        score -= 10;
    }
    if (mammals.at(2)->name() != "mouse") {
        std::cout<<"Mouse's name is incorrect! -10\n";
        score -= 10;
    }
    if (fox->name() != "fox") {
        std::cout<<"Fox's name is incorrect! -10\n";
        score -= 10;
    }

    //Fox part

    std::string thing1 = fox->say();
    std::string thing2 = fox->say();

    std::cout<<"What does the "<<fox->name()<<" say?\n";
    std::cout<<thing1<<"!\n";
    std::cout<<thing1<<"!\n";
    std::cout<<thing1<<"!\n";
    std::cout<<"What does the "<<fox->name()<<" say?\n";
    std::cout<<thing2<<"!\n";
    std::cout<<thing2<<"!\n";
    std::cout<<thing2<<"!\n";

    if (thing1 == thing2) {
        std::cout<<"Foxes don't say the same thing twice!\n";
        score -= 10;
    }

    for (std::vector<Mammal*>::iterator I = mammals.begin(); I != mammals.end(); ++I) {
        delete *I;
    }
    delete fox;
    return 0;
}
Foi útil?

Solução

In addition to the destructor not being virtual, you are returning the address of a local variable. This is undefined behavior.

Mammal* MammalFactory(const std::type_info& ti)
{
    if(ti == typeid(Dog))
    {
        cout << "running dog" << endl;
        Dog D;
        Mammal* dog = &D;
        return dog;  // so what happens to D when MammalFactory returns?
    }
}

You make this same mistake for all the other derived classes. Once that function returns, there is no more "D". It has gone up into a puff of smoke, and you're returning the address of this variable that no longer exists.

Either create a new Mammal (return new Dog;) or come up with a way to create a Dog and return one that isn't local (again, the issue isn't just with this class, but will all of our other classes).

Outras dicas

Some problems:

  • Lacking virtual destructor in base class.
  • Returning dangling pointers, pointers to local objects that have ceased to exist.
  • Exponential increase in memory consumption for foxes, as they bark.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top