Вход виртуальной функции Тип аргумента

Я пытаюсь понять наследование и полиморфизм. Когда я запускаю это:

    #include<iostream> 
    using namespace std; 

class Base 
{ 
int x; 
public: 
    virtual Base* fun() = 0; 
    int getX() { return x; } 
}; 

// This class inherits from Base and implements fun() 
class Derived: public Base 
{ 
    
public: 
    int y;
    Derived* fun() { 
        Derived *d = new Derived;
        d->y = 2;
        return d;
        
    } 
}; 

int main(void) 
{ 
    Derived d;
    Derived *p = d.fun();
  cout<< p->y;
} 

Это прекрасно работает, так как производный класс имеет право переопределять виртуальную функцию, используя другой тип возвращаемого значения, если тип возвращаемого значения является ковариантным с исходным типом возвращаемого значения.

Но что, если виртуальная функция содержит входной аргумент типа Base*. Нравиться :

#include<iostream> 
using namespace std; 

class Base 
{ 
int x; 
public: 
    virtual Base* fun(Base * t) = 0; 
    int getX() { return x; } 
}; 

// This class inherits from Base and implements fun() 
class Derived: public Base 
{ 
    
public: 
    int y;
    Derived* fun(Derived *t) { 
        Derived *d = new Derived;
        d->y = t->y;
        return d;
        
    } 
}; 

int main(void) 
{ 
    Derived d;
    Derived *p = d.fun();
  cout<< p->y;
} 

Это выдает ошибку error: invalid new-expression of abstract class type ‘Derived’ Derived *d = new Derived;, которая, как я понимаю, означает, что компилятор не распознает реализацию виртуальной функции и рассматривает класс «Производный» как абстрактный.

Итак, как мы можем переопределить виртуальную функцию этого типа?? Я пытался найти его, но не нашел никакой ссылки. Если подобный вопрос существует, дайте мне знать. Спасибо

Это невозможно. Вы должны переопределить с тем же именем функции и тем же количеством и типами аргументов.

Yksisarvinen 11.12.2020 11:16

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

bolov 11.12.2020 11:19

Спасибо @Yksisarvinen, теперь я понял, мы можем сохранить аргумент как Base*, но в основной функции мы можем передать Derived*.

Deepak 11.12.2020 11:24
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
238
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если бы мне это было нужно в моем собственном коде. Я бы написал новый производный класс следующим образом:

// This class inherits from Base and implements fun() 
class Derived: public Base 
{ 
    
public: 
    int y;
    Derived* fun(Base *t) { 
        Derived *d = new Derived;
        Derived* input = dynamic_cast<Derived *>(t);
        ASSERT(input);    // Cause the debug version to throw an exception so the error can be debugged
        if (input)
           d->y = t->y;
        else
           d->y = 0;    // Or the default of your choice. 
        return d;
        
    } 
}; 

Это приводит к потенциальной ошибке времени выполнения, если переданный базовый тип не является правильным производным типом. Но я не вижу способа избежать этого.

Другие варианты, которые я вижу, это использование шаблонов. Где производный тип требует передачи производного типа. Или просто создайте новую функцию, которая принимает производный тип в качестве входных данных, а также переопределяет fun(Base *t);

using namespace std;

template <class T>
class Base
{
    int x;
public:
    virtual T* fun(T* t) = 0;
    int getX() { return x; }
};

class Derived : public Base<Derived>
{

public:
    int y;
    Derived() { y = 0; }
    Derived* fun(Derived* t) {
        Derived *d = new Derived;
        d->y = t->y;
        return d;

    }
};

int main(int argc, const char* argv[])
{
    Derived *d = new Derived;
    Derived * p = d->fun(d);
    cout << p->y;
    return 0;
}

тест в визуальной студии 2019.

Другие вопросы по теме