重构出所有类通用的方法
Refactoring out method common to all classes
我有一个全局函数,它可以将一个对象(或类型Source
)的相关位复制到另一个(类型Target
),如下所示:
template<typename Source , typename Target>
void partialCopy( Source& source , Target& target )
{
// perform copy
}
我发现全局函数的问题是,与成员函数不同,在对两个参数中的哪一个进行编码时,并不能立即清楚地知道哪一个是源参数,哪个是目标参数。因此,我希望在每个类中都有一个成员函数partialCopy()
,如下所示:
struct Foo
{
template<typename T>
void partialCopy( T& target )
{
::partialCopy( *this , target );
}
};
现在的问题是必须将成员函数复制到几十个类中。这是复制粘贴编程可以容忍的情况吗?我考虑过将partialCopy
放在头文件partialCopy.h
中,并使用预处理器include将其"注入"到每个类中,如下所示:
struct Foo
{
#include "partialCopy.h"
};
Foo f;
Bar b;
f.partialCopy( b );
虽然这件作品我从未在任何地方见过,也不知道它是否不可接受。
我已经尝试过将partialCopy
成员函数放在一个公共基类中并继承它,但这不起作用,因为this
关键字会引用基类,而不是派生类。
还有更好的选择吗?请告知。
编辑
John的建议(在一个已删除的线程中)让我对CRTP基类中的派生类执行static_cast
,效果很好@约翰请把这个答案贴出来,我会把它标记出来。
我将此作为答案发布,因为在我看来这是合适的。不过,亨里克首先评论道。(然而,这也是我的第一个想法:)
常量引用
使用const&
(常量引用)作为源参数。这样它就很容易与目标区分开来。
额外的好处是,它将验证并确保部分复制函数的常量正确性。
右值参考
您还可以考虑为Source&&
重载它。如果有一些缓冲区是直接复制的,您的函数可能会使用它。
我建议为此重载流运算符。
例如
template<typename Source , typename Target>
void partialCopy(Source& source, Target& target)
{
// perform copy
}
有效地变成:
template<typename Source , typename Target>
void operator>>(const Source& source, Target& target)
{
// perform copy
}
(还要注意,为了清楚起见,Source参数现在是const&。
所以你可以简单地写
Foo f;
Bar b;
f >> b;
使源对象和目标对象更加清晰。
我给出这个答案有点晚了,但我认为您可能对使用CRTP作为复制粘贴编程的干净替代方案感兴趣:
现在的问题是必须将成员函数复制到几十个类中。这是复制粘贴编程可以容忍的情况吗?我考虑过将partialCopy放在一个头文件partialCopy.h中,并使用预处理器include将其"注入"到每个类中[…].
与其复制或#包括代码,不如考虑以下内容:
// common code:
<template typename T>
class PartialCopyImplementer
{
public:
template<typename D>
void partialCopy(D& destination)
{
// ::partialCopy( *this , target );
}
};
// concrete implementations
class Foo1 : public PartialCopyImplementer<Foo1> // CRTP implementation
{
// ...
};
// concrete implementations
class Foo2 : public PartialCopyImplementer<Foo2> // CRTP ensures Foo1 and Foo2
// do not have a common base
{
// ...
};
最干净的方法可能只是将partialCopy
保留为一个自由函数,并以这种方式使用它。这本身并没有什么问题,例如,标准库<algorithm>
标头中的所有函数都是将与对象一起使用的自由函数。
foo.partialCopy(bar)
中的哪个是源,哪个是目的地,也不太清楚。partialCopy
是否将从或复制到bar
?通常,在这种情况下查看文档/函数声明是有用的。如果你有明确的参数名称,并在适当的时候将其设为const
,那么应该很清楚对象的复制方式。
关于:
template<class T>
struct from_impl
{
T const& from;
from_impl(T const& f)
: from(f)
{}
};
template<class T>
from_impl<T> from(T const& f) {
return from_impl(f);
}
template<class T>
struct to_impl
{
T& to;
to_impl(T& t)
: to(t)
{}
};
template<class T>
to_impl<T> to(T& t) {
return to_impl(t);
}
template<class T>
void to(T const&); // prevent using with non-const values
template<class Source,class Target>
void partial_copy(from_impl<Source> source, to_impl<Target> target)
{
// use source.from and target.to to perform copy
}
// usage:
T1 object1;
T2 object2;
partial_copy(from(object1),to(object2));
这非常清楚你想要做什么。from_impl和to_impl的工作方式类似于一种引用,而from和to则作为工厂函数工作,以便于使用。你也可以尝试实现类似的东西。
partial_copy.from(Source).to(Target);
partial_copy(Source)->_(Target);
但正常情况下,这是大量的写作。只需将partial_copy放在自己的命名空间中以防止名称冲突,让用户自己进行自定义重载并使用const&用于发信号通知什么是源和目的地。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- C++重构,扩展方法typedef
- 如何使用C 中的模板重构方法
- 重构后,异步调用方法不再有效
- C++ 重构采用 int 或字符串参数的方法
- 有没有一种方法可以重构C#特有的switch语句
- 如何重构容器以直接使用谓词方法
- 除了一行之外,重构方法基本相同
- 有没有一种方法可以将C++11代码重构为C++代码,这些代码可以由能力较弱的编译器编译
- 如何重构冗余的getter/setter方法
- 重构出所有类通用的方法
- 抽象/重构此开关/案例的好方法是什么?