如何使用类模板删除样板代码?

How to use class templates to remove boiler plate code?

本文关键字:代码 删除 何使用      更新时间:2023-10-16

在下面的示例中,有一个基类和两个派生类。派生类彼此没有什么不同,但我包含它只是为了说明可以有多个子类。该代码创建一个派生类(隐式向上转换,想想工厂设计模式),该类以多态方式克隆到智能指针(与此处所做的完全一样 克隆 std::shared_ptr 在 C++ 中),然后更改类的属性以显示克隆已按预期工作。这运行良好并返回所需的输出"源:4 克隆:1"。我想知道是否可以删除样板代码?

#include "pch.h"
#include <iostream>
class Node
{
public:
Node(int);
int value;
virtual ~Node() = default;
virtual void set_value(int) = 0;
std::shared_ptr<Node> Clone() const;
private:
virtual Node * CloneImplementation() const = 0;
};
Node::Node(int VALUE) {
value = VALUE;
}
std::shared_ptr<Node> Node::Clone() const {
return std::shared_ptr<Node>(CloneImplementation());
};
class DerivedNode1 : public Node
{
public:
DerivedNode1(int);
void set_value(int);
std::shared_ptr<DerivedNode1> Clone() const;
private:
DerivedNode1 * CloneImplementation() const override;
};
DerivedNode1::DerivedNode1(int VALUE) : Node(VALUE) {
}
std::shared_ptr<DerivedNode1>  DerivedNode1::Clone() const {
return std::shared_ptr<DerivedNode1>(CloneImplementation());
};
DerivedNode1 * DerivedNode1::CloneImplementation() const {
return new DerivedNode1(*this);
};
void DerivedNode1::set_value(int NEW_VALUE) {
value = NEW_VALUE;
}
class DerivedNode2 : public Node
{
public:
DerivedNode2(int);
void set_value(int);
std::shared_ptr<DerivedNode2> Clone() const;
private:
DerivedNode2 * CloneImplementation() const override;
};
DerivedNode2::DerivedNode2(int VALUE) : Node(VALUE) {
}
std::shared_ptr<DerivedNode2>  DerivedNode2::Clone() const {
return std::shared_ptr<DerivedNode2>(CloneImplementation());
};
DerivedNode2 * DerivedNode2::CloneImplementation() const {
return new DerivedNode2(*this);
};
void DerivedNode2::set_value(int NEW_VALUE) {
value = NEW_VALUE;
}
std::shared_ptr<Node> ImplicitUpCast(int type) {
if (type == 1) {
return std::make_shared<DerivedNode1>(1);
} else {
return std::make_shared<DerivedNode2>(1);
}
}
int main() {
std::shared_ptr<Node> sourceNode1 = ImplicitUpCast(1);
std::shared_ptr<Node> cloneNode1 = sourceNode1->Clone();
sourceNode1->set_value(4);
std::cout << "Source: " << sourceNode1->value << " Clone: " << cloneNode1->value;
}

在每个子类中制作和声明以下方法似乎很乏味,我想要一个解决方法。

std::shared_ptr<DerivedNode1>  DerivedNode1::Clone() const {
return std::shared_ptr<DerivedNode1>(CloneImplementation());
};
DerivedNode1 * DerivedNode1::CloneImplementation() const {
return new DerivedNode1(*this);
};

我的方法是使用一个"中间"类模板,该模板DerivedNode1DerivedNode2继承自并包含这两种方法。这是我的尝试。

#include "pch.h"
#include <iostream>
class Node
{
public:
Node(int);
int value;
virtual ~Node() = default;
virtual void set_value(int) = 0;
std::shared_ptr<Node> Clone() const;
private:
virtual Node * CloneImplementation() const = 0;
};
Node::Node(int VALUE) {
value = VALUE;
}
std::shared_ptr<Node> Node::Clone() const {
return std::shared_ptr<Node>(CloneImplementation());
};

template<class source>
class NodeExtended : public Node
{
public:
NodeExtended(int);
std::shared_ptr<source> Clone() const;
private:
source* CloneImplementation() const override;
};
template<class source>
NodeExtended<source>::NodeExtended(int VALUE) : Node(VALUE) {
}
template<class source>
std::shared_ptr<source> NodeExtended<source>::Clone() const {
return std::shared_ptr<source>(CloneImplementation());
};
template<class source>
source * NodeExtended<source>::CloneImplementation() const {
return new source(*this);
};
class DerivedNode1 : public NodeExtended<DerivedNode1>
{
public:
DerivedNode1(int);
void set_value(int);
};
DerivedNode1::DerivedNode1(int VALUE) : NodeExtended(VALUE) {
}
void DerivedNode1::set_value(int NEW_VALUE) {
value = NEW_VALUE;
}
class DerivedNode2 : public NodeExtended<DerivedNode2>
{
public:
DerivedNode2(int);
void set_value(int);
};
DerivedNode2::DerivedNode2(int VALUE) : NodeExtended(VALUE) {
}
void DerivedNode2::set_value(int NEW_VALUE) {
value = NEW_VALUE;
}
std::shared_ptr<Node> ImplicitUpCast(int type) {
if (type == 1) {
return std::make_shared<DerivedNode1>(1);
} else {
return std::make_shared<DerivedNode2>(1);
}
}
int main() {
//std::shared_ptr<Node> sourceNode1 = ImplicitUpCast(1);
//std::shared_ptr<Node> cloneNode1 = sourceNode1->Clone();
//sourceNode1->set_value(4);
//std::cout << "Source: " << sourceNode1->value << " Clone: " << cloneNode1->value;
}

我在下一行收到错误"节点扩展::克隆实现":无法将函数定义与现有声明匹配">

source * NodeExtended<source>::CloneImplementation() const {
return new source(*this);
};

我假设这是因为 Node 和源代码不被视为父指针和子指针,并且多态性由于返回类型而崩溃,类似于智能指针在这种情况下可能引发错误的方式。

我不确定如何从这里继续。我认为我对类模板的理解不够好,但没有教程真正捕捉到我的用例。

任何和所有的帮助将不胜感激。

编辑:

批准的答案找到了主要问题,但我还必须将一些源返回类型更改为仍然提供所需行为的节点。这是完整的解决方案。

#include "pch.h"
#include <iostream>
class Node
{
public:
Node(int);
int value;
virtual ~Node() = default;
virtual void set_value(int) = 0;
std::shared_ptr<Node> Clone() const;
private:
virtual Node * CloneImplementation() const = 0;
};
Node::Node(int VALUE) {
value = VALUE;
}
std::shared_ptr<Node> Node::Clone() const {
return std::shared_ptr<Node>(CloneImplementation());
};

template<class source>
class NodeExtended : public Node
{
public:
NodeExtended(int);
std::shared_ptr<source> Clone() const;
private:
Node * CloneImplementation() const override;
};
template<class source>
NodeExtended<source>::NodeExtended(int VALUE) : Node(VALUE) {
}
template<class source>
std::shared_ptr<source> NodeExtended<source>::Clone() const {
return std::shared_ptr<source>(static_cast<source*>(CloneImplementation()));
};
template<class source>
Node * NodeExtended<source>::CloneImplementation() const {
return new source(static_cast<const source&>(*this));
};
class DerivedNode1 : public NodeExtended<DerivedNode1>
{
public:
DerivedNode1(int);
void set_value(int);
};
DerivedNode1::DerivedNode1(int VALUE) : NodeExtended(VALUE) {
}
void DerivedNode1::set_value(int NEW_VALUE) {
value = NEW_VALUE;
}
class DerivedNode2 : public NodeExtended<DerivedNode1>
{
public:
DerivedNode2(int);
void set_value(int);
};
DerivedNode2::DerivedNode2(int VALUE) : NodeExtended(VALUE) {
}
void DerivedNode2::set_value(int NEW_VALUE) {
value = NEW_VALUE;
}
std::shared_ptr<Node> ImplicitUpCast(int type) {
if (type == 1) {
return std::make_shared<DerivedNode1>(1);
} else {
return std::make_shared<DerivedNode2>(1);
}
}
int main() {
std::shared_ptr<Node> sourceNode1 = ImplicitUpCast(1);
std::shared_ptr<Node> cloneNode1 = sourceNode1->Clone();
sourceNode1->set_value(4);
std::cout << "Source: " << sourceNode1->value << " Clone: " << cloneNode1->value;
}

CRTP 的问题在于类还不是一个完整的类型。 这使得可克隆更加困难,并且需要一些强制转换。

template<class source>
class NodeExtended : public Node
{
public:
using Node::Node; // inherit constructors
std::shared_ptr<source> Clone() const
{
return std::shared_ptr<source>(static_cast<source*>(CloneImplementation()));
}
private:
// Cannot use covariant return type as source is not complete.
Node* CloneImplementation() const override
{
return new source(static_cast<const source&>(*this));
}
};

std::shared_ptr<DerivedNode1> DerivedNode1::Clone() conststd::shared_ptr<DerivedNode2> DerivedNode2::Clone() const示例中未调用。没有这些功能,一切正常。在函数中的模板示例中

template<class source>
source * NodeExtended<source>::CloneImplementation() const {
return new source(*this);
};

您尝试调用source(NodeExtended &)构造函数。你需要类似的东西

return new source(*static_cast<const source*>(this));

那么一切都应该工作。