виртуальная функция с вектором пользовательского типа

#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 forvirtual 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'». Однако «защищенный» — это полезная подсказка.