Как использовать производный параметр в переопределяющей функции без динамического приведения - PullRequest
0 голосов
/ 02 июля 2019

Может кто-нибудь дать мне знать, как достичь:

  • параметр метода производного класса, являющийся производным классом параметра (не базовым классом параметра)?

Вот чего я хочу:

class Base{
public:
    // Base class method has ParameterBase parameter
    virtual void f(ParameterBase pb) = 0;
}

class Derived : public Base{
public:
    // I want: Derived class method has ParameterDerived parameter;
    void f(ParameterDerived pd){ //do something with pd; }
}

class ParameterBase{
    // Base class of parameter;
}

class ParameterDerived : public ParameterBase{
    // Derived class of parameter;
}

Как добиться выше?Нужно ли использовать ParamterBase в списке параметров производного метода и dynamic_cast параметр в теле метода?

Ответы [ 2 ]

1 голос
/ 02 июля 2019

Функция, которую вы запрашиваете, называется контр-дисперсией типа параметра.И C ++, к сожалению, не поддерживает это.C ++ поддерживает только ковариацию возвращаемого типа. См. здесь для хорошего объяснения.

Возможно, неудобно, C ++ не позволяет нам писать функцию, отмеченную hmm ... выше.Классическая ООП-система C ++ поддерживает «ковариантные типы возврата», но не поддерживает «контравариантные типы параметров».

Но вы можете использовать оператор dynamic_cast<>().Но сначала вы должны изменить тип параметра на указатель или ссылку и добавить по крайней мере один виртуальный член (в том числе виртуальный деструктор) в class ParameterBase, чтобы компилятор создал для него таблицу виртуальных методов.Вот код со ссылками.Вместо них можно использовать указатели.

class ParameterBase
{
    public:
        // To make compiler to create virtual method table.
        virtual ~ParameterBase()
        {}
};

class ParameterDerived : public ParameterBase
{
};


class Base
{
    public:
        // Pointers or references should be used here.
        virtual void f(const ParameterBase& pb) = 0;
};

class Derived : public Base
{
    public:
        virtual void f(const ParameterBase& pb) override
        {
            // And here is the casting.
            const ParameterDerived& pd=dynamic_cast<const ParameterDerived&>(pb);

        }
};


int main()
{
    Derived d;
    ParameterDerived p;

    d.f(p);
}
0 голосов
/ 02 июля 2019

Предположим, вы хотите, чтобы Derived вызывался с ParameterDerived, но вы также хотите объявить интерфейс в абстрактных базовых классах.

Интерфейс ДОЛЖЕН иметь те же типы параметров, но вы все равно можете использовать правильный подкласс параметров с помощью dynamic_cast внутри Derived :: f

#include <iostream>
#include <string>

// interface
struct ParameterBase {
    virtual ~ParameterBase() {};
};

struct Base {
    virtual void f(ParameterBase *pb) = 0;
    virtual ~Base() {};
};

// specific
struct ParameterDerived : public ParameterBase {
    std::string name;
    ParameterDerived(const std::string &name) : name(name) {}
    ParameterDerived& operator=(const ParameterDerived& rhs) { name = rhs.name; }
    ~ParameterDerived() {};
};

struct Derived : public Base {
    Derived(){}
    Derived& operator=(const Derived &rhs) {}
    virtual ~Derived(){}

    void f(ParameterBase *pb) {
        ParameterDerived *pd = dynamic_cast<ParameterDerived*>(pb);
        if (pd) {
            std::cout << "Derived object with derived parameter " << pd->name << std::endl;
        } // else {throw std::exception("wrong parameter type");}
    }
};

int main() {
    Derived object;
    ParameterDerived param("foo");
    object.f(&param);
}
...