可以在基类中定义副本构造函数,并且仍然可以处理派生类情况吗?

时间:2019-12-19 18:17:45

标签: c++ copy virtual c++03

我的类结构如下:

class P {
    public:
        virtual std::auto_ptr<P> clone() const=0;
};

class A : public P {
    public:
        std::auto_ptr<P> clone() const {
            return std::auto_ptr<P>(new A(*this));
        }
};

class B : public P {
    public:
        std::auto_ptr<P> clone() const {
            return std::auto_ptr<P>(new B(*this));
        }
};

class C : public P {
    public:
        std::auto_ptr<P> clone() const {
            return std::auto_ptr<P>(new C(*this));
        }
};

这只是复制构造函数的代码:类ABC的代码全部不同。这里有很多代码重复,可以简化吗?

3 个答案:

答案 0 :(得分:1)

使用CRTP,您可以这样做:

library(purrr)
out <- map2_dfr(lst1, lst2, ~ map2_dfr(.x, map(.y, "date"),
        ~ cbind(.x, date = .y), .id = 'IDGroup2'), .id = 'IDGroup')
head(out)
#  IDGroup   IDGroup2    holiday         temp        wind   humidity    barometer    weekday weekend workday_on_holiday weekend_on_holiday
#1       5 2016-01-01 -0.2875051 -0.004131595 -0.68942320 0.08788958 -0.044270176 0.08152994       0       -0.004491160                  0
#2       5 2016-01-01 -0.2613214  0.075470507  0.15884757 0.11554980 -0.027390966 0.11183146       0       -0.004928516                  0
#3       5 2016-01-01 -0.2788497  0.148605376  0.84752327 0.08082478 -0.110819362 0.07685963       0       -0.009905681                  0
#4       5 2016-01-01 -0.2852835 -0.011284750  0.11122661 0.13438693 -0.013517623 0.09257593       0       -0.005359963                  0
#5       5 2016-01-01 -0.2827380  0.012600235 -0.08916214 0.16819011  0.017435972 0.07898130       0       -0.005911979                  0
#6       5 2016-01-01 -0.2799886  0.055347286 -0.29320240 0.07062373 -0.009474599 0.08682005       0       -0.004491160                  0
#  protocol_active   text_fog text_light_rain text_mostly_cloudy text_passing_clouds     text_rain text_scattered_clouds   text_sunny    month_1
#1               0 0.05453610      0.02055504       -0.003508107         0.011477915  0.0248998813           -0.08106078 0.0086088600 0.07640738
#2               0 0.07014788      0.03472626       -0.010609524         0.014214168 -0.0004061495           -0.07777867 0.0031850194 0.16343993
#3               0 0.02396879      0.03373001       -0.008926486         0.008658116 -0.0329548903           -0.17243122 0.0063267332 0.08468129
#4               0 0.06937934      0.02769369        0.007768817         0.023657059 -0.0005894799           -0.08510636 0.0009107648 0.15761615
#5               0 0.07031541      0.02747060       -0.024575127         0.014786102  0.0011341455           -0.07967515 0.0057251817 0.07625937
#6               0 0.04563824      0.02055504       -0.014174540         0.014693571 -0.0004061495           -0.09679305 0.0106474124 0.08535635
#      month_2       month_3     month_4     month_5      month_6     month_7     month_8    month_9   month_10   month_11   month_12       date
#1 0.045578238  0.0033622182 -0.06274214 -0.07467288 -0.032955777 -0.01001179 -0.03556978 0.01872355 0.07136117 0.05808590 0.15059333 2010-01-01
#2 0.018249372  0.0044576218 -0.17375310 -0.14704236 -0.007879189 -0.01295435 -0.04510764 0.01888210 0.07714521 0.08734045 0.25044793 2010-01-02
#3 0.002464291 -0.0292761438 -0.08312281 -0.08700808 -0.007707109 -0.01470387 -0.04435510 0.01596025 0.05754736 0.05717132 0.08667592 2010-01-03
#4 0.039944258 -0.0004514736 -0.15914200 -0.15421098 -0.008650888 -0.01224635 -0.04510764 0.01888210 0.07671589 0.08638439 0.17999160 2010-01-04
#5 0.047762766  0.0162581336 -0.14487271 -0.08386189 -0.008392147 -0.01224635 -0.04510764 0.01905395 0.07042630 0.11087914 0.11585888 2010-01-05
#6 0.022514986  0.0057770289 -0.13264991 -0.10598666 -0.037495021 -0.01280877 -0.03657964 0.01905395 0.07222101 0.08583542 0.17929509 2010-01-06

为了使派生类的实类型受益,我将代码修改为:

template <typename Derived, typename Base>
struct Clonable : public Base
{
    std::auto_ptr<Base> clone() const {
        return std::auto_ptr<Base>(new Derived(static_cast<const Derived&>(*this)));
    }
};

class A : public Clonable<A, P> {}; 
class B : public Clonable<B, P> {}; 
class C : public Clonable<C, P> {}; 

因此,以下内容有效:

class P {
public:
    std::auto_ptr<P> clone() const { return std::auto_ptr<P>(vclone()); }
private:
    virtual P* vclone() const = 0;
};

template <typename Derived, typename Base>
struct Clonable : public Base
{
    std::unique_ptr<Derived> clone() const {
        return std::unique_ptr<Derived>(static_cast<Derived*>(vclone()));
    }
private:
    // Cannot use covariant-type `Derived*` in CRTP as Derived is not complete yet
    Base* vclone() const {
        return new Derived(static_cast<const Derived&>(*this));
    }
};

class A : public Clonable<A, P> {}; 
class B : public Clonable<B, P> {}; 
class C : public Clonable<C, P> {}; 

答案 1 :(得分:0)

  

可以在基类中定义副本构造函数并且仍然处理派生类情况吗?

通常,简短的回答是“否”。

如果编译器生成的副本构造函数足够,则可以正常工作。

如果定义了一个派生类,使得编译器生成的副本构造函数不足,则无法解决在派生类中定义一个的需求。

答案 2 :(得分:0)

如果您的意思是说是否有一种方法可以给每个派生类一个克隆方法,而不必显式地写出来:答案是否定的。如果将元类添加到C ++中,这将成为可能,但不要指望在一段时间内使其成为语言。

但是,Boost.Any可以在不知道其动态类型的情况下复制对象,并且可以在C ++ 03中实现。如果愿意,可以使用类似的类型擦除技术。简而言之,它将包括:

  • 具有虚拟ClonablePBase方法和虚拟析构函数的clone
  • ClonableP派生的ClonablePBase类模板。类型为ClonableP<T>的对象(其中T是从P派生的)持有一个T对象,并且知道如何使用T的副本构造函数对其自身进行克隆。
  • 包含AnyP的{​​{1}}类。它通过调用虚拟克隆方法来复制自身。