pointers — вызов методов подкласса из суперкласса в векторном переполнении стека

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

Я изучил 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
}

}

5

Решение

Чтобы получить полиморфное поведение, которое вы хотите, вам нужно добавить 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 спецификатор

Живой пример без virtual спецификатор

3

Другие решения

Вы должны объявить методы как 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"); }
};
0

Метод должен быть виртуальный.
В 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
};
0

Я думаю, что вам не хватает virtual ключевое слово в объявлении вашего метода. Если вы хотите получить метод подкласса при вызове методов в родительском классе, методы должны быть объявлены virtual,

0

Если вы не используете указатель, вы получите «нарезку объекта» при копировании объекта в вектор. Это уменьшает объект до базового типа, объявленного в аргументе шаблона вектора. Таким образом, нет подкласса, поэтому нет метода подкласса для вызова, даже если метод является виртуальным.

0
По вопросам рекламы [email protected]