2016-01-30 32 views
-1

我有一個Animal的數組。C++:多態:調用超級函數

默認情況下,Animal表示"Animal"

我也有Cat,它擴展了Animal並且改爲"Meow"

我也有Dog,它延伸Animal並且說"Woof"代替。

我想要什麼:

Animal* a[2]; 
a[0] = new Cat(); 
a[1] = new Dog(); 
a[0]->talk(); //Meow 
a[1]->talk(); //Woof 

會發生什麼:

Animal* a[2]; 
a[0] = new Cat(); 
a[1] = new Dog(); 
a[0]->talk(); //Animal 
a[1]->talk(); //Animal 

//頭

class Animal { 
public: 
    Animal(); 
    ~Animal(); 
    int talk() {return 0;} 
}; 

class Cat : public Animal { 
public: 
    Cat(); 
    ~Cat(); 
    int talk() {return 1;} 
}; 

class Dog : public Animal { 
public: 
    Dog(); 
    ~Dog(); 
    int talk() {return 2;} 
}; 

//.cpp

void letsHear(Animal *a) { 
    _LOG_INFO() << a->talk(); 
} 

int main(){ 
    Animal* a[2]; 
    a[0] = (Animal *)new Cat(); 
    a[1] = (Animal *)new Dog(); 

    letsHear((Animal *)new Cat()); //0 
    letsHear((Animal *)new Dog()); //0 
    letsHear(new Animal()); //0 
    letsHear(a[0]); //0 
    letsHear(a[1]); //0 
    return 0; 
} 
Cat::Cat() {} 
Cat::~Cat(){} 
Dog::Dog() {} 
Dog::~Dog() {} 
Animal::Animal() {} 
Animal::~Animal() {} 
+1

這不是合法的C++。 – Puppy

+0

所以指針現在可以使用'.'?你有沒有試過'a [1] - > talk();' – dtech

+0

我剛修好'.'。 – RainingChain

回答

1

您必須聲明您的基本方法talk()virtual函數。 看看這個例子。

class Animal { 
public: 
    virtual void talk() { 
     cout << "Animal" << endl; 
    } 
}; 

class Cat : public Animal { 
public: 
    void talk() { 
     cout << "Meow" << endl; 
    } 
}; 

class Dog : public Animal { 
public: 
    void talk() { 
     cout << "Woof" << endl; 
    } 
}; 

然後,你可以調用你的方法,如你的例子。

Animal *a[2]; 
a[0] = new Cat(); 
a[1] = new Dog(); 
a[0]->talk(); //Meow 
a[1]->talk(); //Woof 
3

爲了獲得在C++中多態行爲,則必須聲明功能virtual。這是一個好主意,使析構函數虛也處於任何多的基類:

class Animal { 
public: 
    Animal(); 
    virtual ~Animal(); 
    virtual int talk() {return 0;} 
}; 
1

你想要什麼叫做dynamic dispatch,就是選擇功能在運行時動態調用,基於對象的,其成員之一的類型你想打電話的功能。

在C++中,這是通過使用virtual member functions來完成的。要使用它們,在你的基類中聲明相應的成員函數virtual

#include <iostream> 
#include <array> 
#include <memory> 
using namespace std; 

struct Animal { 
    virtual void speak() const { 
     cout << "Animal" << endl; 
    } 
    virtual ~Animal() {} // Better add this, too! 
}; 
struct Cat : public Animal { 
    virtual void speak() const override { 
     cout << "Meow" << endl; 
    } 
}; 
struct Dog : public Animal { 
    virtual void speak() const override { 
     cout << "Wuff" << endl; 
    } 
}; 

int main() { 
    array<unique_ptr<Animal>, 3> animals; 
    animals[0] = make_unique<Cat>(); 
    animals[1] = make_unique<Dog>(); 
    animals[2] = make_unique<Animal>(); 
    for (auto const & a : animals) { 
     a->speak(); 
    } 
    return 0; 
} 

(Live example)

如果(任何)您的派生類添加成員字段,這些類的任何實例的所有權在一些指向基本類型的指針(如我的例子)中,那麼你應該遵循aschelper的建議,並使基礎破壞者virtual。否則,你會得到內存泄漏。

你可以看到,我使用標準庫中的一些概念,我的代碼一樣unique_ptrarray以及在for循環類型推斷。使用這些應該在適當的時候完成,在大多數情況下使用原始數組/指針不再是必要的,並且容易導致內存管理錯誤。