繁体   English   中英

为两个相似的类定义一次成员函数?

[英]Define member functions once for two similar classes?

是否可以避免为下面的结构A、B定义相同的函数两次? 它们的成员命名完全相同,但v0, v1 ... vN成员在两个结构AB之间属于不同类型。 如果它有帮助,成员v * 都来自同一个结构V

非平凡的函数(即赋值 =)可以在结构之外重用模板化的复制函数,如下所示,但如果在结构内定义一次,它会是首选/更干净的。

有没有一种干净的方法可以将AB定义模板化为一个?

template <class T1, class T2>
void copy(T1& to, T2& from)
{
    to.v0 = from.v0;
    to.v1 = from.v1;
    to.type = from.type;
}

enum class E { TYPE_0, TYPE_1 };

struct B;

struct A 
{
    C0<float> v0;
    C1<int> v1;
    E type;

    A& operator = (const B& t)
    {
        copy(*this, t);
        return *this;
    } 
    
    string strType() { return string(type); }    
};

struct B
{
    D0<float> v0;
    D1<int> v1;
    E type;

    B& operator = (const A& t)
    {
        copy(*this, t);
        return *this;
    } 

    string strType() { return string(type); }
}

您可以为通用功能保留一个common基模板类,并为类AB继承它。

但是,复制赋值运算符是一种特殊的成员函数,我认为不能在基类中为不同类型返回模板。 因此,您需要为每个类提供。

意思是,你可以做

enum class E { TYPE_0, TYPE_1 };
struct B;

template<typename ClassA, typename ClassB> struct Common
{
   template<E type> 
   std::string strType() { return std::to_string(static_cast<int>(type)); }
   // need to cast the type to int before you convert std::to_string

   // other common-member-functions
};

struct A : public Common<A, B>
{
   C0 v0;
   C1 v1;
   E type;
   // ... A& operator = (const B& t)
   // bring the common functionalities to A
   using Common<A, B>::strType;
   // ... other member-functions
};

struct B : public Common<B, A>
{
   D0 v0;
   D1 v1;
   E type;
   // ... B& operator = (const A& t)
   // bring the common functionalities to A
   using Common<B, A>::strType;
   // ... other member-functions
};

但是,结构AB似乎仅与两个成员不同(即分别为C0C1D0D1 ),通过创建类模板将两个类合并为一个,也是一种替代方法:

下面是一个示例代码:

#include <iostream>
#include <vector>
#include <string>

enum class E { TYPE_0, TYPE_1 };

template<typename T1,  typename T2>
struct AandB
{
   T1 v0;
   T2 v1;
   E type;
   AandB() : type{ E::TYPE_0 } {}
   AandB& operator= (const AandB& rhs) // one operator =
   {
      v0 = rhs.v0;
      v1 = rhs.v1;
      type = rhs.type;
      return *this;
   }

   std::string strType() const { return std::to_string(static_cast<int>(type)); }
};

int main()
{
   using C0 = std::vector<float>;
   using C1 = std::vector<int>;
   AandB<C0, C1> obj;
   std::cout << obj.strType() ; // Prints: 0
}

这正是称为 CRTP(Curious Recurring Template Pattern)的模式的用例。

这个想法是定义一个基类模板,将派生类作为模板参数。 然后您可以安全地将基类中的this强制转换为派生类并访问基类中的派生类成员。

这也适用于复制赋值运算符。

#include <string>
#include <iostream>

template<typename Derived>
struct CRTPBase {
    
    Derived& self() { return static_cast<Derived&>(*this); }
    const Derived& self() const { return static_cast<const Derived&>(*this); }

    std::string strType() { return self().type;}

    template<class OtherDerived>
    Derived& operator=(const CRTPBase<OtherDerived>& other) {
        self().type = other.self().type;
        return self();
    }
};

struct A : public CRTPBase<A>
{
   using Base = CRTPBase<A>;
   std::string type = "A";

   using Base::operator=;
};

struct B :  public CRTPBase<B>
{
      using Base = CRTPBase<B>;
   std::string type = "B";

   using Base::operator=;
};

int main() {

    A a;
    B b;
    std::cout << a.strType() << std::endl; // Prints: A
    std::cout << b.strType() << std::endl; // Prints: B
    
    a = b;
    
    std::cout << a.strType() << std::endl; // Now prints: B
}

现场示例在这里

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM