C ++协方差返回类型的缺点是什么? [英] What are the drawbacks of C++ covariance return types?

查看:59
本文介绍了C ++协方差返回类型的缺点是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近不得不处理C ++ 协方差返回类型,例如以下结构:

I have recently had to deal with C++ covariance return types such as the following construct :

struct Base
{
     virtual ~Base();
};
struct Derived : public Base {};

struct AbstractFactory
{
    virtual Base *create() = 0;
    virtual ~AbstractFactory();
};

struct ConcreteFactory : public AbstractFactory
{
    virtual Derived *create()
    {
        return new Derived;
    }
};

它允许客户端代码在需要时尤其是在不使用的情况下,将 Derived 对象视为 Base 类型或作为 Derived 类型 dynamic_cast static_cast .

It allows the client code to treat the Derived object as a Base type or as a Derived type when needed and especially without the use of dynamic_cast or static_cast.

这种方法的缺点是什么?这是不良设计的征兆吗?

What are the drawbacks of this approach ? Is it a sign of bad design ?

谢谢.

推荐答案

在C ++中实现的协变返回类型的主要限制是它们只能与原始指针和引用一起使用.没有真正的理由在可能的情况下使用它们,但局限性意味着我们不能在需要它们时始终使用它们.

The chief limitation of covariant return types as implemented in C++ is that they only work with raw pointers and references. There are no real reasons not to use them when possible, but the limitation means we cannot always use them when we need them.

很容易克服此限制,同时提供相同的用户体验,而无需依赖语言功能.就是这样.

It is easy to overcome this limitation while providing identical user experience, without ever relying to the language feature. Here's how.

让我们使用常见且流行的非虚拟接口重写我们的类成语.

Let's rewrite our classes using the common and popular non-virtual interface idiom.

struct AbstractFactory
{
    Base *create() {
      return create_impl();
    }

  private:
    virtual Base* create_impl() = 0;
};

struct ConcreteFactory : public AbstractFactory
{
    Derived *create() {
      return create_impl();
    }

  private:
    Derived *create_impl() override {
        return new Derived;
    }
};

现在,这里发生了一些有趣的事情. create 不再是虚拟的,因此可以具有任何返回类型.它不受协变量返回类型规则的约束. create_impl 仍然受约束,但是它是私有的,除了类本身,没有人调用它,因此我们可以轻松地对其进行操作并完全删除协方差.

Now here something interesting happens. create is no longer virtual, and therefore can have any return type. It is not constrained by the covariant return types rule. create_impl is still constrained, but it's private, no one is calling it but the class itself, so we can easily manipulate it and remove covariance altogether.

struct ConcreteFactory : public AbstractFactory
{
    Derived *create() {
      return create_impl();
    }

  private:
    Base *create_impl() override {
        return create_impl_derived();
    }

    virtual Derived *create_impl_derived() {
        return new Derived;
    }
};

现在 AbstractFactory ConcreteFactory 都具有与以前完全相同的接口,并且看不到协变返回类型.对我们意味着什么?这意味着我们可以自由使用智能指针.

Now both AbstractFactory and ConcreteFactory has exactly the same interface as before, without a covariant return type in sight. What does it mean for us? It means we can use smart pointers freely.

// replace `sptr` with your favourite kind of smart pointer

struct AbstractFactory
{
    sptr<Base> create() {
      return create_impl();
    }

  private:
    virtual sptr<Base> create_impl() = 0;
};

struct ConcreteFactory : public AbstractFactory
{
    sptr<Derived> create() {
      return create_impl();
    }

  private:
    sptr<Base> create_impl() override {
        return create_impl_derived();
    }

    virtual sptr<Derived> create_impl_derived() {
        return make_smart<Derived>();
    }
};

在这里,我们克服了语言限制,并为类提供了等效的协变返回类型,而不必依赖于有限的语言功能.

Here we overcame a language limitation and provided an equivalent of covariant return types for our classes without relying on a limited language feature.

注意技术倾向.

    sptr<Base> create_impl() override {
        return create_impl_derived();
    }

此处的此函数将 Derived 指针隐式转换("upcasts")为 Base 指针.如果我们使用该语言提供的协变返回类型,则编译器会在需要时自动插入这种向上转换.不幸的是,该语言只有足够的聪明才能对原始指针进行处理.对于其他所有事情,我们必须自己做.幸运的是,如果有点冗长,这相对容易.

This here function implicitly converts ("upcasts") a Derived pointer to a Base pointer. If we use covariant return types as provided by the language, such upcast is inserted by the compiler automatically when needed. The language is unfortunately only smart enough to do it for raw pointers. For everything else we have to do it ourselves. Luckily, it's relatively easy, if a bit verbose.

(在这种特殊情况下,只返回一个 Base 指针可能是可以接受的.我不在此讨论.我假设我们绝对需要类似的东西协变量返回类型.)

(In this particular case it could be acceptable to just return a Base pointer throughout. I'm not discussing this. I'm assuming we absolutely need something like covariant return types.)

这篇关于C ++协方差返回类型的缺点是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆