Я пытаюсь добавить несколько подклассных элементов в вектор, перебрать их, вызывая переопределенный метод, и хочу, чтобы он вызывал переопределенный метод, где это возможно. Однако я обнаружил, что он, кажется, вызывает только метод суперкласса.
Я изучил Java и не уверен, почему он делает это на C ++. Я попытался переписать код, используя вектор указателей суперкласса и приведя указатель подкласса к суперклассу. Доступ к этому через указатели тогда работает.
В идеале я не хочу помещать список указателей в вектор, так как тогда я должен вручную удалить каждый из них (я верю?), Чтобы остановить утечки памяти, так как я буду создавать объекты с новыми, чтобы они сохранялись после вызова метода добавить их в вектор.
Есть ли лучший способ сделать это, или я застрял с использованием указателей и вызова удаления на созданных объектах, когда родительский класс не нужен? Предпочтительно, чтобы вектор представлял собой список класса X, а не список указателей класса X
Моя структура:
class a { vector vec of class X,
method to create and add an instance of X into vector vec,
method to create and add an instance of Y into vector vec }
class X { talk() }
class Y : public X { talk() }
Код, демонстрирующий то, что я в идеале хочу сделать, но показывающий его неработоспособным, только вызывая метод суперкласса:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
class A {
public:
virtual void talk() { printf("A\n"); }
};
class B: public A {
public:
void talk() { printf("B\n"); }
};
int main(void) {
std::vector<A> vec;
std::vector<A*> vec2;
A a;
B b;
a.talk();
b.talk();
vec.push_back(a);
vec.push_back(b);
vec2.push_back(&a);
vec2.push_back(&b);
for(int i = 0; i < vec.size(); i++) {
vec[i].talk();
vec2[i]->talk(); //bad but short for example
}
}
Чтобы получить полиморфное поведение, которое вы хотите, вам нужно добавить virtual
спецификатор функций в базовом классе, которые вы хотите переопределить в производных классах.
class A {
public:
virtual void talk() { printf("A\n"); }
};
Вы должны также сделать привычку добавлять override
спецификатор переопределенных функций в производных классах, чтобы компилятор мог помочь вам в решении подобных проблем.
class B: public A {
public:
virtual void talk() override { printf("B\n"); }
// ^ Compiler will report an error if base class' function
// is not virtual.
};
Также вы не можете назначить производный объект экземпляру базового класса, или нарезка будет происходить.
std::vector<A> vec;
/* ... */
B b;
/* ... */
vec.push_back(b); // Slicing. Information only in B is lost.
Вы должны объявить методы как virtual
чтобы иметь возможность переопределить их в подклассе. Также рекомендуется сделать виртуальный деструктор.
class A {
public:
virtual void talk() { printf("A\n"); }
virtual ~A(){}
};
class B: public A {
public:
// using virtual is not really necessary here, but it's good for clarity.
virtual void talk() { printf("B\n"); }
};
Метод должен быть виртуальный.
В java методы являются виртуальными по умолчанию.
class A {
public:
virtual void talk() { printf("A\n"); }
};
class B: public A {
public:
virtual void talk() override { printf("B\n"); } //override key word is in C++ 0x and above
};
Я думаю, что вам не хватает virtual
ключевое слово в объявлении вашего метода. Если вы хотите получить метод подкласса при вызове методов в родительском классе, методы должны быть объявлены virtual
,
Если вы не используете указатель, вы получите «нарезку объекта» при копировании объекта в вектор. Это уменьшает объект до базового типа, объявленного в аргументе шаблона вектора. Таким образом, нет подкласса, поэтому нет метода подкласса для вызова, даже если метод является виртуальным.