2014-11-02 16 views
-2

У меня есть базовый класс Animal и два производных класса Bird и Fish. У меня есть две виртуальные функции: fly(int) и swim(int) в Animal для Bird и Fish соответственно. Существует общая функция aliveSince() в AnimalВиртуальная функция должна возвращать значение в MS C++

class Animal{ 
public: 
    Animal() { 
    age = 0; 
    } 
    virtual ~Animal(){} 
    static Animal* factory(int type); 
    int aliveSince(){ 
    return age; 
    } 
    virtual int fly(int m){} //error, needs a return value 
    virtual int swim(int m){} //error, needs a return value 

private: 
    int age; 
}; 

class Bird: public Animal{ 
public: 
    Bird(){ 
    totalFlight = 0; 
    } 
    int fly(int m){ 
    cout<<"Bird flew "<<m<<" metres\n"; 
    return totalFlight = totalFlight+m; 
    } 
private: 
    int totalFlight; 
}; 

class Fish: public Animal{ 
public: 
    Fish(){ 
    totalSwim = 0; 
    } 
    int swim(int m){ 
    cout<<"Fish swam "<<m<<" metres underground\n"; 
    return totalSwim = totalSwim + m; 
    } 
private: 
    int totalSwim; 
}; 

Animal* Animal::factory(int type){ 
    if (type) return new Bird(); 
    else return new Fish(); 
} 

Я хочу использовать эти классы, как это:

Animal *a = Animal::factory(1); //Bird 
Animal *b = Animal::factory(0); //Fish 
a->aliveSince(); 
b->aliveSince(); 
a->fly(5); 
b->swim(5); 

Я компиляции в MS VC++ и генерирует ошибки, Animal::fly и Animal::swim необходимо возвращаемое значение , Однако это компилируется в GNU C++. Как я могу избавиться от ошибки, не указывая возвращаемое значение в виртуальных методах?

Обратите внимание, что я не могу сделать эти функции чисто виртуальные, как это сделало бы класс Animal абстрактны и все производные классы должны реализовать fly() и swim()

+1

Возможно, вам захотелось написать 'virtual int fly (int m) = 0;' –

+0

Не будет ли абстрактного класса класса Animal в таком случае, который я не могу сделать? Я уже указал это в описании проблемы. –

+1

_ «Обратите внимание, что я не могу сделать эти функции чистыми виртуальными, так как это приведет к абстрактному классу Animal» _ Затем вы должны вернуть некоторые разумные значения по умолчанию. –

ответ

2

UPDATE: Просто видел, как вы не можете использовать чистый виртуальные методы, потому что вам нужно определенное значение по умолчанию.

Если вам требуется значение по умолчанию, вам лучше вернуть его явно, вместо того чтобы позволить компилятору (или случайному) решить возвращаемое значение. Так просто возвращает 0.

ORIGINAL

Если вы не предоставите любую реализацию в вашем базовом классе, использовать Pure Virtual методы. Например:

class Animal 
{ 
public: 
    virtual int fly(int m) = 0; 
    virtual int swim(int m) = 0; 
}; 

Метод Pure-Virtual - это метод, который не имеет тела. Он делает абстракцию базового класса Animal - вы не сможете создавать какие-либо его экземпляры, а только производные классы, реализующие эти методы.

+0

Скажем, если я сделаю эти методы чистыми виртуальными, мне нужно будет определить метод 'fly' в классе' Fish' или я могу его избежать? –

+0

Я предполагаю, что мне нужно будет определить все виртуальные методы в производном классе, иначе это не позволит мне создавать объекты 'Bird' или' Fish'? –

+0

Все конкретные классы должны иметь реализации (либо сами, либо в базовом классе). – zmbq

1

Обе функции должны возвращать значение, как вы уже догадались:

virtual int fly(int m){ return 0; } 
virtual int swim(int m){ return 0; } 

Либо, положить взамен 0; в обеих областях. Это будет ваш ответ «как вы просите».

Или попробуйте somything так, чтобы упростить код:

class Animal{ 
public: 
    Animal() 
    { 
    totalMoved = 0; 
    } 
    virtual ~Animal(){} 
    virtual int move(int m) 
    { 
    totalMoved += m; 
    cout<<"Total distance " << totalMoved << std::endl; 
    return totalMoved ; 
    } 

protected: 
    int totalMoved; 
}; 

class Bird: public Animal{ 
public: 
    int move(int m) 
    { 
    cout<<"Bird flew "<<m<<" metres\n"; 
    return Animal::move(m); 
    } 
}; 

class Fish: public Animal{ 
public: 
    int swim(int m){ 
    cout<<"Fish swam "<<m<<" metres underground\n"; 
    return Animal::move(m); 
    } 
}; 

Конкретные алгоритмы для перемещения могут быть записаны в птицах и класса Fish. Общая сумма может быть разделена, поэтому делите ее. Это концепция программирования ООП и не позволяет вам делать что-то двойное.

Добавили вывод консоли в Animal, чтобы вы могли видеть, что происходит, когда.

+0

В таком случае вы можете придумать функцию 'move'. Это был просто упрощенный пример, который я создал. Не всегда можно сделать что-то подобное в большом проекте. Например, я пытаюсь реализовать производные классы для FTP и SFTP с использованием базового класса FileTransfer, и некоторые функции очень сильно различаются в двух протоколах. –

+0

Тогда ваш пример не подходит. Функциональность написана в Fish :: move(), а в Bird :: move() все равно totalMove (или totalUploadBytes) будет/может использоваться совместно. Не вызвав Animal :: move() в обоих случаях, потоки классов на 100% будут обладать собственной функциональностью, что сделает потомка ответственным за добавление к totalMoved. Но вызовите Animal :: move(), может (с учетом FTP/SFTP) обрабатывать некоторые общие события. – brainoverflow

+0

такие события, как std :: function OnBytesReceived; if (OnBytesReceived) OnBytesReceived(); – brainoverflow