容器 class 并通过继承调用虚方法
Container class and calling virtual methods with inheritance
我确定我遗漏了一些东西,但我真的无法在互联网上找到任何我的代码无法按预期工作的原因:
#include <stdio.h>
#include <iostream>
#include <fstream>
#include "string.h"
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
using namespace std;
class Animal {
private:
char *name;
protected:
enum { tele, empty } bendo;
public:
Animal() {};
Animal(const char *kname) : bendo(empty) {
name = new char[strlen(kname) + 1];
strcpy(name, kname);
}
const char *getname() { return name; }
virtual ~Animal() {
cout << "~" << name << endl;
delete[] name;
}
virtual void print(std::ostream& os) const {
os << "Animal.print" << std::endl;
}
};
class Monkey : public Animal {
protected:
static const char* SOUND;
public:
Monkey(const char *kname) : Animal(kname) { }
~Monkey() { cout << SOUND << SOUND << " "; }
virtual void print(std::ostream& os) const {
os << "Monkey.print" << std::endl;
}
};
const char* Monkey::SOUND = "Mak";
class Tiger : public Animal {
public:
Tiger(const char *kname) : Animal(kname) { }
virtual void print(std::ostream& os) const {
os << "Tiger.print" << std::endl;
}
};
class Cage{
Animal* animals;
unsigned int num;
public:
Cage(){};
~Cage();
void add(const Animal* a) {
Animal* tmp = new Animal[num + 1];
for (unsigned int i = 0; i < num; i++)
tmp[i] = animals[i];
tmp[num++] = *a;
cout << "param: ";
a->print(std::cout);
cout << "in cage: ";
tmp[num - 1].print(std::cout);
animals = tmp;
}
void print(std::ostream& os) {
for (unsigned int i = 0; i < num; i++){
animals[i].print(os);
}
}
};
int main() {
Animal *animal = new Animal("Animal");
Animal *cicus = new Tiger("Cicus");
Animal *csita = new Monkey("Csita");
Animal *tarzan = new Monkey("AIAIAIAI");
Cage* cage = new Cage;
cout << "add animal" << endl;
cage->add(animal);
cout << endl << "add cicus" << endl;
cage->add(cicus);
cout << endl << "add csita" << endl;
cage->add(csita);
cout << endl << "add tarzan" << endl;
cage->add(tarzan);
cout << endl << "cage->print(cout);" << endl;
cage->print(cout);
cin.get();
}
基本上,我想在这里做的是:
- 我有一个 class(笼子)用来存放动物。
- 每种动物都有一个 print(...) 方法。
如果我调用 cage.print(...),我希望它调用所有动物的 print(...) 方法 (Monkey.print(... ), Tiger.print(...), 等), 但它总是调用 Animal.print(...) 方法。对于此代码,这是输出:
add animal
param: Animal.print
in cage: Animal.print
add cicus
param: Tiger.print
in cage: Animal.print
add csita
param: Monkey.print
in cage: Animal.print
add tarzan
param: Monkey.print
in cage: Animal.print
cage->print(cout);
Animal.print
Animal.print
Animal.print
Animal.print
我在这里错过了什么?我做错了什么?
解决方案
好吧,正如@rodrigo 所说,我 运行 进入了所谓的 'object slicing' 错误,为了避免这种情况,我不得不将 Animal* animals
替换为 Animal** animals
,所以我存储的不是 Animal对象但动物 POINTERS。我只是在这里复制代码的重要部分,所以它只展示了这个特定问题的解决方案,所以要小心,它遗漏了其他东西(比如内存处理!)。
class Cage{
Animal** animals; // We need to store pointers!
unsigned int num;
unsigned int max;
public:
Cage(){
num = 0;
max = 10;
animals = new Animal*[max];
};
void add(Animal* a) {
/* Here I just 'optimized' a bit,
but of course the best would be to use linked list. */
if (num == max) {
max*=2;
Animal** tmp = new Animal*[max];
for (unsigned int i = 0; i < num; i++) {
tmp[i] = animals[i];
}
animals = tmp;
}
animals[num++] = a;
}
}
问题是您的 animals
变量是 Animal
的数组,您需要一个指针或引用才能具有多态行为。
您无法构建引用数组,因此您需要一个指针数组:Animal **animals
.
例如,当您将 Monkey
复制到 Animal
时,您实际上所做的是复制对象的动物部分并丢失猴子部分。这就是所谓的拼接,几乎总是要避免的。
PS:你应该使用std::string
和std::vector
而不是管理你自己的内存。
我确定我遗漏了一些东西,但我真的无法在互联网上找到任何我的代码无法按预期工作的原因:
#include <stdio.h>
#include <iostream>
#include <fstream>
#include "string.h"
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
using namespace std;
class Animal {
private:
char *name;
protected:
enum { tele, empty } bendo;
public:
Animal() {};
Animal(const char *kname) : bendo(empty) {
name = new char[strlen(kname) + 1];
strcpy(name, kname);
}
const char *getname() { return name; }
virtual ~Animal() {
cout << "~" << name << endl;
delete[] name;
}
virtual void print(std::ostream& os) const {
os << "Animal.print" << std::endl;
}
};
class Monkey : public Animal {
protected:
static const char* SOUND;
public:
Monkey(const char *kname) : Animal(kname) { }
~Monkey() { cout << SOUND << SOUND << " "; }
virtual void print(std::ostream& os) const {
os << "Monkey.print" << std::endl;
}
};
const char* Monkey::SOUND = "Mak";
class Tiger : public Animal {
public:
Tiger(const char *kname) : Animal(kname) { }
virtual void print(std::ostream& os) const {
os << "Tiger.print" << std::endl;
}
};
class Cage{
Animal* animals;
unsigned int num;
public:
Cage(){};
~Cage();
void add(const Animal* a) {
Animal* tmp = new Animal[num + 1];
for (unsigned int i = 0; i < num; i++)
tmp[i] = animals[i];
tmp[num++] = *a;
cout << "param: ";
a->print(std::cout);
cout << "in cage: ";
tmp[num - 1].print(std::cout);
animals = tmp;
}
void print(std::ostream& os) {
for (unsigned int i = 0; i < num; i++){
animals[i].print(os);
}
}
};
int main() {
Animal *animal = new Animal("Animal");
Animal *cicus = new Tiger("Cicus");
Animal *csita = new Monkey("Csita");
Animal *tarzan = new Monkey("AIAIAIAI");
Cage* cage = new Cage;
cout << "add animal" << endl;
cage->add(animal);
cout << endl << "add cicus" << endl;
cage->add(cicus);
cout << endl << "add csita" << endl;
cage->add(csita);
cout << endl << "add tarzan" << endl;
cage->add(tarzan);
cout << endl << "cage->print(cout);" << endl;
cage->print(cout);
cin.get();
}
基本上,我想在这里做的是:
- 我有一个 class(笼子)用来存放动物。
- 每种动物都有一个 print(...) 方法。
如果我调用 cage.print(...),我希望它调用所有动物的 print(...) 方法 (Monkey.print(... ), Tiger.print(...), 等), 但它总是调用 Animal.print(...) 方法。对于此代码,这是输出:
add animal param: Animal.print in cage: Animal.print add cicus param: Tiger.print in cage: Animal.print add csita param: Monkey.print in cage: Animal.print add tarzan param: Monkey.print in cage: Animal.print cage->print(cout); Animal.print Animal.print Animal.print Animal.print
我在这里错过了什么?我做错了什么?
解决方案
好吧,正如@rodrigo 所说,我 运行 进入了所谓的 'object slicing' 错误,为了避免这种情况,我不得不将 Animal* animals
替换为 Animal** animals
,所以我存储的不是 Animal对象但动物 POINTERS。我只是在这里复制代码的重要部分,所以它只展示了这个特定问题的解决方案,所以要小心,它遗漏了其他东西(比如内存处理!)。
class Cage{
Animal** animals; // We need to store pointers!
unsigned int num;
unsigned int max;
public:
Cage(){
num = 0;
max = 10;
animals = new Animal*[max];
};
void add(Animal* a) {
/* Here I just 'optimized' a bit,
but of course the best would be to use linked list. */
if (num == max) {
max*=2;
Animal** tmp = new Animal*[max];
for (unsigned int i = 0; i < num; i++) {
tmp[i] = animals[i];
}
animals = tmp;
}
animals[num++] = a;
}
}
问题是您的 animals
变量是 Animal
的数组,您需要一个指针或引用才能具有多态行为。
您无法构建引用数组,因此您需要一个指针数组:Animal **animals
.
例如,当您将 Monkey
复制到 Animal
时,您实际上所做的是复制对象的动物部分并丢失猴子部分。这就是所谓的拼接,几乎总是要避免的。
PS:你应该使用std::string
和std::vector
而不是管理你自己的内存。