如何在没有动态转换的情况下在覆盖函数中使用派生参数

How to use derived parameter in an overriding function without dynamic casting

谁能告诉我如何实现:

这就是我想要的:

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 参数?

假设您希望使用 ParameterDerived 调用 Derived,但您还想在抽象基类中声明接口 类。

接口必须具有相同的参数类型,但您仍然可以在 Derived::f

中使用 dynamic_cast 强制执行正确的参数子类
#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);
}

您要求的功能称为参数类型 contra-variance。不幸的是,C++ 不支持它。 C++ 仅支持 return 类型协变。 See 这里有一个很好的解释。

Perhaps inconveniently, C++ does not permit us to write the function marked hmm... above. C++’s classical OOP system supports “covariant return types,” but it does not support “contravariant parameter types.”

但您可以使用 dynamic_cast<>() 运算符。但首先,您必须将参数类型更改为指针或引用,并向您的 class ParameterBase 添加至少一个虚拟成员(虚拟析构函数也算在内),以使编译器为其创建虚拟方法 table 。这是带有参考的代码。可以使用指针代替。

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);
}