Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在接受抽象基类指针的函数中使用派生类操作_C++_Polymorphism - Fatal编程技术网

C++ 在接受抽象基类指针的函数中使用派生类操作

C++ 在接受抽象基类指针的函数中使用派生类操作,c++,polymorphism,C++,Polymorphism,假设我有一个抽象基类,它有两个派生类。每个派生类都有一些抽象基类中不存在的新功能,但两个派生类都有相同的功能。例如: class MyBase: public: /* ... */ virtual void DoSomething() = 0; /* ... */ class MyAlpha : public MyBase public: /* ... */ void DoSomething()

假设我有一个抽象基类,它有两个派生类。每个派生类都有一些抽象基类中不存在的新功能,但两个派生类都有相同的功能。例如:

class MyBase:
    public:
        /* ... */
        virtual void DoSomething() = 0;
        /* ... */


class MyAlpha : public MyBase
    public:
        /* ... */
        void DoSomething() { /* does sometihng */ }

        /* Function not present in abstract base class */
        void DoSomethingNew() { /* does something new */ }
        /* ... */

class MyBeta : public MyBase
    public:
        /* ... */
        void DoSomething() { /* does sometihng */ }

        /* Function not present in abstract base class */
        void DoSomethingNew() { /* does something new */ }
        /* ... */
template <typename Base_t> void MyOperation(std::unique_ptr<Base_t> &base_object) { 
    /* some ops */
    base_object->DoSomethingNew();
}
现在我有一个模板函数,在我的例子中,它接受指向基类的std::unique_ptr指针,我希望能够调用DoSomethingNew函数,即存在于两个派生类中但不存在于基类中的函数。例如:

class MyBase:
    public:
        /* ... */
        virtual void DoSomething() = 0;
        /* ... */


class MyAlpha : public MyBase
    public:
        /* ... */
        void DoSomething() { /* does sometihng */ }

        /* Function not present in abstract base class */
        void DoSomethingNew() { /* does something new */ }
        /* ... */

class MyBeta : public MyBase
    public:
        /* ... */
        void DoSomething() { /* does sometihng */ }

        /* Function not present in abstract base class */
        void DoSomethingNew() { /* does something new */ }
        /* ... */
template <typename Base_t> void MyOperation(std::unique_ptr<Base_t> &base_object) { 
    /* some ops */
    base_object->DoSomethingNew();
}
我该怎么做呢?我觉得模板专门化可能是解决这个问题的方法,但我不太确定。我正在用一个新特性扩展一个开源库,所以我对现有代码的修改有限制,我可以/应该修改哪些代码来使我的特性工作。我的实际用例中的基类是我希望避免修改的代码,但是对于这个库中的一般用途,我的函数签名需要接受指向基类的指针

由于基类是虚拟的,因此实际使用情况如下:

std::unique_ptr<MyBase> object = std::unique_ptr<MyAlpha>(new MyAlpha);
MyOperation(object);
如何在MyOperation函数中使用派生类功能来实现这一点?如果有区别,我必须保持与C++11兼容。

当您需要从指向基的指针向下转换或交叉转换到派生类中时,动态转换是存在的。在您的示例中,它看起来像这样:

std::unique_ptr<MyBase> object = std::unique_ptr<MyAlpha>(new MyAlpha);
// ...
dynamic_cast<MyAlpha*>(object.get())->DoSomethingNew();
void SomethingSimple(std::unique_ptr<MyBase> base) {
    MyMiddle* derived = dynamic_cast<MyMiddle>(base.get());
    if (derived == nullptr) {
        // derived wasn't of the correct type, recover in a reasonable way.
        return;
    }
    derived->DoSomethingNew();
}
您可以阅读更多关于它的内容,但正如我在评论中提到的,太多的内容表明您有设计问题。特别是在这里,当您在两个派生类中都具有该功能时,它可以很容易地移动到基类中

作为dynamic_cast的替代方案,因为您无法修改基类,所以可以创建自己的基类,从不可修改的基类继承,并将接口自定义为实际使用的接口

class NewBase : public MyBase
{
public:
    void DoSomething() = 0;
    void DoSomethingNew() = 0;
};

std::unique_ptr<NewBase> object  = std::unique_ptr<MyAlpha>(new MyAlpha);
// ...
object->DoSomethingNew();
每个派生类都有一些抽象基类中不存在的新功能,但两个派生类都有相同的功能

然后在一个可能抽象的中间类中捕获:

class MyMiddle : public MyBase {
    public:
        virtual void DoSomethingNew() = 0;
};

class MyAlpha : public MyMiddle {
    public:
        void DoSomething() override;
        void DoSomethingNew() override;
};

class MyBeta : public MyMiddle {
    public:
        void DoSomething() override;
        void DoSomethingNew() override;
};
通过这种方式,您可以通过引用MyMiddle来实现DoSomethingNew的通用功能,从而避免大量代码重复

现在我有一个模板函数,在我的例子中,它接受指向基类的std::unique_ptr指针,我希望能够调用DoSomethingNew函数

由于您只有一个指向基类的指针,编译器将不允许您在该基类上调用派生类的方法。但是,如果您期望实现实际上是派生类的实例,则可以强制转换为该实例

使用动态_cast检查派生类是否为预期类型,如果是,则将其用作该类型。如果您100%完全确定参数将始终是派生类的参数,请使用静态类型转换,无论是现在还是将来。换句话说,不要。去做动态演员

请注意,动态_cast可用于原始指针,但不可用于unique_ptr。因此,您有两种选择:要么保留指向base的唯一指针,要么使用指向派生对象的原始指针进行访问。或者在复杂的多步骤过程中投射指针。只有当您希望在需要派生类型的上下文中保持指针更长时间时,后者才有意义。简单的情况如下:

std::unique_ptr<MyBase> object = std::unique_ptr<MyAlpha>(new MyAlpha);
// ...
dynamic_cast<MyAlpha*>(object.get())->DoSomethingNew();
void SomethingSimple(std::unique_ptr<MyBase> base) {
    MyMiddle* derived = dynamic_cast<MyMiddle>(base.get());
    if (derived == nullptr) {
        // derived wasn't of the correct type, recover in a reasonable way.
        return;
    }
    derived->DoSomethingNew();
}
但以下仍然不会调用专用函数:

    std::unique_ptr<MyBase> object(new MyAlpha());
    MyOperation(object);

尽管对象动态地包含一个MyAlpha,但它的静态类型是指向MyBase的唯一指针,这就是驱动模板参数的原因。因此,我看不出这样的专业化对你有什么帮助。

动态演员阵容会起到作用,但太多这样的角色通常表明设计不好。因为两个派生类都有DoSomethingNew成员函数,所以最好将其添加到您的基类中class@crdrisko:我也是这么想的。看看这个库,所有的派生类实际上都包含这个函数,所以可以使用它。然而,我怀疑创造者离开基类是有原因的。也许为了这个问题,我们应该假设还有其他派生类不执行DeMethTimeNeX.@ McCman:你所发布的不是C++。它甚至不作为C++编译。没有虚拟基类,也没有任何类型的基类。@marcman:我希望能够调用DoSomethingNew函数,如果您使用指向基类的指针,那么您就不希望能够调用它。这就是指向基类的指针的意思。这并不能解决这个问题,但虚拟基类指的是虚拟继承的基类。例如,派生类:公共虚拟基{};。虚拟基地带来了一些复杂性。这里的不是虚拟基类;它是一个抽象类,也就是一个类
它有一个或多个纯虚拟函数。谢谢你提供了非常全面的答案。这真是信息量大!