2013-10-09 14 views
3

Почему я не могу использовать абстрактный класс, например интерфейс во время выполнения.Невозможно создать экземпляр абстрактного класса с помощью C++ 11

Я получаю результат:

1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(615): error C2259: 'Creature' : cannot instantiate abstract class 
1>   due to following members: 
1>   'std::string Creature::Move(std::vector<std::string,std::allocator<_Ty>> &)' : is abstract 
1>   with 
1>   [ 
1>    _Ty=std::string 
1>   ] 

1>   visual studio 2013\projects\cpp_demo\cpp_demo\creature.h(9) : see declaration of 'Creature::Move' 
1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(614) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' 
1>   with 
1>   [ 
1>    _Ty=Creature 
1>   ] 

1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(752) : see reference to function template instantiation 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' being compiled 
1>   with 
1>   [ 
1>    _Ty=Creature 
1>   ] 

1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\type_traits(580) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled 
1>   with 
1>   [ 
1>    _Ty=Creature 
1>   ] 

1>   c:\program files (x86)\microsoft visual studio 12.0\vc\include\vector(650) : see reference to class template instantiation 'std::is_empty<_Alloc>' being compiled 
1>   with 
1>   [ 
1>    _Alloc=std::allocator<Creature> 
1>   ] 

1>   visual studio 2013\projects\cpp_demo\cpp_demo\main.cpp(7) : see reference to class template instantiation 'std::vector<Creature,std::allocator<_Ty>>' being compiled 
1>   with 
1>   [ 
1>    _Ty=Creature 
1>   ] 

Мой код:

int main() 
{ 
    unique_ptr<vector<Creature>> pCreatures(new vector<Creature>); 

    unique_ptr<Creature> pHuman(new Human()); 
    pCreatures->push_back(*pHuman); 
} 



#include "stdafx.h" 
#include "Creature.h" 

class Human : public Creature 
{ 
public: 
    virtual string Move(vector<string> &log); 
}; 



#include "stdafx.h" 
#include "IMove.h" 

class Creature : public IMove 
{ 
public: 
    virtual string Move(vector<string> &log) = 0; 
    virtual string GetState(vector<string> &log); 
}; 

Пожалуйста, помогите.

ответ

4

Вы можете использовать абстрактный класс в vector или unique_ptr, например.

#include <vector> 
#include <memory> 

using namespace std; 

class Interface { 
public: 
    virtual ~Interface() = 0; 
}; 

Interface::~Interface() {} 

class Implementation : public Interface { 
}; 

int main(int argc, char** argv) { 
    unique_ptr<Interface> p(new Implementation); 
    vector<unique_ptr<Interface>> v; 
    v.emplace_back(new Implementation); 
    vector<Interface> vi; 
    // This leads to compile error: vi.emplace_back(); 
} 

Кроме того, вы можете использовать vector<Interface> до тех пор, пока вы не вызывать любые методы, которые потенциально называет new Interface. Например, если вы просто объявляете переменную vector<Interface> v;, она компилируется, но если вы push_back или emplace_back или resize, тогда у нее будет ошибка компиляции, потому что они назовут new Interface.

Приведенный выше код проверен в соответствии с gcc-4.6.3.

+2

Попытка хранить производный класс в '' вектора потерпит неудачу, однако. Контейнер, который никогда не может содержать ничего, мало используется. –

+0

@JonathanPotter Если вы попытаетесь сохранить производный объект в 'vector ', тогда у вас будет усеченный объект. Поэтому мое предложение, никогда не делайте этого. Это C++, это не Java. Буквенный буфер памяти хранит сам объект, а не их указатели. –

+0

Итак, как я могу хранить разные производные классы в коллекции, которая хранит общий интерфейс? –

0

Вы можете использовать, но вместо использования:

unique_ptr<vector<Creature>> pCreatures(new vector<Creature>); 

использование

vector<unique_ptr<Creature>> pCreatures; 

так что вы будете иметь векторов Существа указателей, управляемых unique_ptr.

Есть, по крайней мере, два способа использования этого вектора:

  1. Создание объектов непосредственно в вектор:

    pCreatures.emplace_back (новый Human());

  2. Перемещение unique_ptr к нему:

    unique_ptr pHuman (новый человек());

    pCreatures.push_back (move (pHuman));

Ниже компактное использование:

int main() 
{ 
    vector<unique_ptr<Creature>> pCreatures; 

    pCreatures.emplace_back(new Human()); 

    unique_ptr<Creature> pHuman(new Human()); 
    pCreatures.push_back(move(pHuman)); 

    // example of usage 
    pCreatures[0]->Move(); 
} 
+2

ВСЕГДА ИСПОЛЬЗУЙТЕ 'new Human' вместо' new Human() '.См. Http://stackoverflow.com/questions/620137/do-the-parentheses-after-the-type-name-make-a-difference-with-new. Разница заключается в 'new Human()' zero initialize fields, которые не инициализируются конструктором и, следовательно, медленнее. Также он скроет ошибки в вашем конструкторе. Если правильность вашего конструктора зависит от того, как звонит его вызывающий ('new Human()' vs 'new Human'), то это ошибка. Поэтому хороший письменный конструктор должен всегда создавать действительный объект. Поэтому «новый человек» всегда должен использоваться. –

+0

, как вы сказали, в некоторых случаях есть разница, и в этих случаях «новый X» быстрее, чем «новый X()», и помогает отображать ошибки забывания инициализации. Поэтому 'new X' всегда не хуже, чем' new X() 'и в некоторых случаях лучше. Почему у вас нет привычки всегда использовать 'new X' вместо' new X() '? –

+0

BTW: ваша претензия ОЧЕНЬ неверна, что члены POD неинициализированы только тогда, когда «структура состоит только из POD или имеет конструктор, сгенерированный компилятором». В структуре, отличной от POD, если у вас есть поле POD 'm', но опустить' m() 'в определяемом пользователем конструкторе, оно НЕИНИТАЛИЗИРОВАНО. В C++, где важна производительность, ничего не инициализируется, если вы не укажете его явно ('new X()' или 'm()' также являются явными способами сообщить компилятору, который вы хотите его инициализировать). Забудьте о предположении, что компилятор будет инициализировать членов для вас. Также забудьте о 'new X()', но используйте C++-путь 'new X'. Это C++, а не Java. –

Смежные вопросы