是否可以动态地转换“这个”作为返回值? [英] Is it ok to dynamic cast "this" as a return value?

查看:124
本文介绍了是否可以动态地转换“这个”作为返回值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这更像是一个设计问题。

This is more of a design question.

我有一个模板类,我想根据模板类型添加额外的方法。为了实现DRY原理,我得出这个模式(有意省略定义):

I have a template class, and I want to add extra methods to it depending on the template type. To practice the DRY principle, I have come up with this pattern (definitions intentionally omitted):

template <class T>
class BaseVector: public boost::array<T, 3>
{
protected:
    BaseVector<T>(const T x, const T y, const T z);
public:
    bool operator == (const Vector<T> &other) const;
    Vector<T> operator + (const Vector<T> &other) const;    
    Vector<T> operator - (const Vector<T> &other) const;
    Vector<T> &operator += (const Vector<T> &other)
    {
        (*this)[0] += other[0];
        (*this)[1] += other[1];
        (*this)[2] += other[2];

        return *dynamic_cast<Vector<T> * const>(this);
    }

    virtual ~BaseVector<T>()
    {
    }
}

template <class T>
class Vector : public BaseVector<T>
{
public:
    Vector<T>(const T x, const T y, const T z)
    : BaseVector<T>(x, y, z)
    {
    }
};

template <>
class Vector<double> : public BaseVector<double>
{
public:
    Vector<double>(const double x, const double y, const double z);
    Vector<double>(const Vector<int> &other);
    double norm() const;
};

我打算让BaseVector成为一个实现细节。这工作,但我关心 operator + = 。我的问题是:是这个指针的动态转换代码气味吗?有没有更好的方式来实现我想做的(避免代码重复,并在用户代码中不必要的转换)?或者我是安全的,因为BaseVector构造函数是私有的?

I intend BaseVector to be nothing more than an implementation detail. This works, but I am concerned about operator+=. My question is: is the dynamic cast of the this pointer a code smell? Is there a better way to achieve what I am trying to do (avoid code duplication, and unnecessary casts in the user code)? Or am I safe since, the BaseVector constructor is private?

对不起, dtor,但我忘了粘贴它,代码不编译没有它。

Sorry, yes I have virtual dtor, but I forgot to paste it, the code doesn't compile without it.

推荐答案

我建议你考虑一个替代方法(请注意,在下面的示例中,我已将代码简化为所需的最小值,以演示替代方法)。

I would recommend that you consider an alternative approach (note that in the below examples, I have simplified the code to the bare minimum required to demonstrate the alternative approaches).

首先,考虑奇怪的循环模板参数(CRTP):

First, consider the Curiously Recurring Template Parameter (CRTP):

template <typename T, typename DerivedVector>
struct BaseVector
{
    DerivedVector& operator+=(DerivedVector const& other)
    {
        return static_cast<DerivedVector&>(*this);
    }
};

template <typename T>
struct Vector : BaseVector<T, Vector<T>>
{
};

由于你总是知道派生类型是什么,所以 static_cast 就足够了。如果 Vector< T> 是唯一基类为 BaseVector 的类, code> T 参数总是相同的,严格来说,CRTP参数是不必要的:你总是知道派生类型是什么,所以一个 static_cast

Since you always know what the derived type is, a static_cast is sufficient. If Vector<T> is the only class whose base is BaseVector<T> and if you are guaranteed that the T parameters are always the same, then strictly speaking, the CRTP parameter is unnecessary: you always know what the derived type is, so a static_cast is safe.

或者,考虑运算符不必是成员函数,因此可以声明非成员运算符函数模板:

Alternatively, consider that operators need not be member functions, so you could declare non-member operator function templates:

template <typename T, typename DerivedVector>
struct BaseVector
{
};

template <typename T>
struct Vector : BaseVector<T, Vector<T>>
{
};

template <typename T>
Vector<T>& operator+=(Vector<T>& self, Vector<T> const& other)
{
    return self;
}

虽然后者更适合运算符,非操作员成员函数,因此CRTP方法将优先于那些。

While the latter is preferable for operators, it won't work for ordinary, nonoperator member functions, so the CRTP approach would be preferable for those.

这篇关于是否可以动态地转换“这个”作为返回值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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