#c #templates #implementation #virtual-functions
#c #шаблоны #реализация #виртуальные функции
Вопрос:
Я хочу определить абстрактный базовый класс с вектором структурных переменных и виртуальной функцией, которая будет реализована производными классами:
class TestFather {
private:
struct myStruct
{
// struct definition
};
vector<myStruct> myStructVect;
public:
virtual vector<myStruct> get_myStructVect() = 0;
};
но когда я пишу производный класс:
#include "TestFather.h"
class TestSon : public TestFather{
private:
struct myStruct
{
// struct definition
};
vector<myStruct> myStructVect;
public:
vector<myStruct> get_myStructVect();
};
Я получаю эту ошибку:
invalid covariant return type for ‘virtual std::vector<ProvaSon::myStruct, std::allocator<ProvaSon::myStruct> > ProvaSon::get_myStructVect()’
Я делаю что-то неправильно или, может быть, я пытаюсь сделать что-то, что запрещено языком?
Комментарии:
1. Почему вы дважды переопределяете MyStruct?
2. Хорошо, это была «человеческая ошибка» 🙂
Ответ №1:
Эти два myStruct
типа совершенно не связаны. Это означает, что вы пытаетесь переопределить TestFather::get_myStructVect()
и заставить ее возвращать совершенно другой тип. Это недопустимо.
Комментарии:
1. Неверно в последнем пункте — потому что он возвращает их векторы, а не указатели на них.
2. Да — то, что у них одинаковое имя, не означает, что они одинаковые!
Ответ №2:
Вам не нужно переопределять структуру в TestSon
, и вы также не можете этого сделать. Вызывающая функция fatherptr->get_myStructVect
статически получает vector<TestFather::myStruct>
ответ, поэтому компилятор запрещает вам переопределять функцию базового класса подобным образом, потому что динамически возвращаемый объект потенциально был бы несовместим с vector<TestFather::myStruct>
(кто знает, что вы вводите TestSon::myStruct
и как vector
отличается поведение от базового класса vector?).
Что касается допустимого различия, C допускает, чтобы возвращаемый тип производного класса был производным типом возвращаемого класса базового класса, и только тогда, когда возвращаемые типы являются указателями или ссылками.
Ответ №3:
Это запрещено. Поскольку вы переопределили MyStruct в своем производном классе, vector<MyStruct> — это другой тип в производном классе, чем в базовом классе. Это две разные myStructs.
Вы можете только изменить возвращаемый тип этой виртуальной функции на что-то, унаследованное от возвращаемого типа, объявленного в базовом классе. Но vector<TestSon::MyStruct> не наследуется от vector<TestFather::MyStruct>
Ответ №4:
Там говорится vector<myStruct>
, но поскольку вы изменили myStruct
в дочернем классе, на самом деле это два разных типа, поэтому каждая из двух функций считает, что возвращает другой тип. Это разрешено только для ковариантных типов, где тип связан с фактическим типом класса, содержащего функцию.
Обратите внимание, что вам, вероятно, в любом случае не следует возвращать вектор атрибута класса по значению здесь.
Я не могу сказать, что вы на самом деле собираетесь делать, но вложенные структуры действительно не должны иметь одно и то же имя, если это две разные вещи (и если они одинаковы, не переопределяйте это). Моя первая внутренняя реакция заключается в том, что, возможно, отношения родитель-потомок здесь неуместны. Рассматривали ли вы другие варианты? Если вам действительно нужно вернуть другой тип в дочернем элементе, а родительский элемент не знает об этом, то вы не можете использовать виртуальный интерфейс для этого. Вам следует просто присвоить функциям разные имена, чтобы вы знали, каким должен быть возвращаемый тип.
С более подробной информацией о ваших целях может быть предоставлен лучший ответ.
Комментарии:
1. Моя цель — определить ряд подклассов, которые имеют общую структуру данных, поэтому я думаю, что выбор интерфейса является подходящим. Я хочу, чтобы эти классы выполняли разные действия с одними и теми же данными, и я хочу наложить некоторую форму ограничения на структуру этих данных (поэтому я выбрал interface).
Ответ №5:
Дублирующая частная структура немного странная в вашем примере. Приведенное ниже отлично компилируется, например:
тестовый отец класса {
protected:
struct myStruct
{
// struct definition
};
vector<myStruct> myStructVect;
public:
virtual vector<myStruct> get_myStructVect() = 0;
};
class TestSon : public TestFather{
public:
vector<myStruct> get_myStructVect();
};
int main(int argc, char**argv)
{
TestSon testSon;
}
Обратите внимание на замену private на protected, что позволяет производным классам получать доступ к определению родительской структуры и хранилищу myStructVect.
Комментарии:
1. Нет, это не так, g возвращает «неопределенную ссылку на `vtable для TestSon'». Однако «защищенный» — это полезная подсказка.