gpt4 book ai didi

c++ - 如何根据参数的类型实例化不同的类?

转载 作者:搜寻专家 更新时间:2023-10-31 00:28:55 25 4
gpt4 key购买 nike

我有一个名为 Type 的虚拟类,以及派生类 Type1 和 Type2。

class Type {
public:
virtual void print() = 0;
};
class Type1 : public Type {
public:
void print() { cout << "I am of type 1" << endl; }
};
class Type2 : public Type {
public:
void print() { cout << "I am of type 2" << endl; }
};

根据用户输入的参数,我将实例化一个类或另一个类。

然后我想要另一个类来产生 Action ,这取决于作为参数给出的“Type”对象的类型。现在,这个类是:

class Action {
protected:
Type *t;
public:
Action(Type *t) : t(t) {} ;
void print() {
cout << "I am an action. My type says: ";
t->print();
}
};

如何让 Action::print 根据属性“t”的类型产生不同的任务?

我尝试过的:

  • 创建两个派生类,即 Action1 和 Action2,如果我实例化 Type1(分别为 Action2 和 Type2),则实例化 Action1。但这正是我不想做的事情:我希望 Action“自己”知道该做什么。
  • 将 Action 定义为模板类(用模板类型替换 Type)。但以同样的方式,我必须实例化一个类型为 Action 或 Action 的对象,这是我不想做的。

我的愿望是有一个看起来像这样的 main:

int main(int argc, const char * argv[]) {
Type *t = new Type1();

Action *act = new Action(t);
act->print();

delete act, t;
return 0;
}

但是根据 t 的类型调用不同的打印方法。这可能(以及如何)吗?


编辑

看了评论,发现主要有两种可能的设计:

  1. 创建一个类Action,并调用特定的方法(print(Type1 *) 或print(Type2 *))。我认为这是评论中建议的访问者模式。

  2. 创建两个类,Action1 和 Action2(可能派生自 Action,也可能不是!),并实例化对应于 t、Type1 或 Type2 的类。

一种解决方案是否比另一种更清洁、更易于维护等?


编辑2

一些评论中提到的工厂模式呢?谁能告诉我它是否解决了我的问题?

最佳答案

首先要注意一点:我个人认为“使用 namespace ”是一种不好的做法,因为它会影响头文件。原因在整个互联网上都有描述。

此外,由于异常安全性,我总是尽量减少使用指针。 Sutter 有一本关于它的好书,叫做 Exceptional C++,它非常详细地描述了这些问题。然而,指针显然有其用途,其中一个特别是多态性。最后,如果类只有公共(public)成员,我喜欢将它们设为结构体……这只是个人喜好问题。

让我们从一些代码开始:

#include <string>
#include <iostream>
#include <memory>

struct Type
{
virtual void print() = 0;
};

struct Type1 : Type
{
void print() { std::cout << "I am of type 1" << std::endl; }
};

struct Type2 : Type
{
void print() { std::cout << "I am of type 2" << std::endl; }
};

class Action
{
protected:
std::unique_ptr<Type> t;
public:
Action(std::unique_ptr<Type> &&t) : t(std::move(t)) {};

void print()
{
std::cout << "I am an action. My type says: ";
t->print();
}
};

int main()
{
Action act(std::make_unique<Type1>());
act.print();

return 0;
}

您似乎要解决的第一个问题是用户输入会生成类型。根据输入,这可能指向一个抽象工厂或构建器模式,甚至是一个成熟的解析器,但如果这是一个简单的输入决定,最好 KISS:

int main()
{
std::string s;
std::getline(std::cin, s);

std::unique_ptr<Type> type;

if (s == "1")
{
type = std::make_unique<Type1>();
}
else
{
type = std::make_unique<Type2>();
}

Action act(std::move(type));
act.print();

return 0;
}

不过,通常您希望将模型与实现分开。 Action 有很多不同的形状和形式,所以您可能想根据您的模型做其他事情。访问者模式、双重 dispatch 或任何你想称呼的模式都会在这里派上用场。

请注意,我通常使用稍微修改过的访问器,它默认返回基本类型。这样,您可以轻松地将转换合并到您的代码中,恕我直言,这是一个常见的设计要求。在这一点上,我只是要使用指针。就我个人而言,我非常喜欢内存领域来解决内存管理问题,但我认为这超出了这个答案的范围。

最后,一个简单的基类可以帮助您摆脱无意义的管道。

struct TypeVisitor;

struct Type
{
virtual Type* Accept(TypeVisitor& visitor) = 0;
};

template <typename T>
struct TypeBase : Type
{
virtual Type* Accept(TypeVisitor& visitor) override
{
return visitor.Handle(static_cast<T*>(this));
}
};

struct Type1 : TypeBase<Type1>
{
};

struct Type2 : TypeBase<Type2>
{
};

struct TypeVisitor
{
virtual Type* Handle(Type1* input)
{
/* if necessary, recurse here like: input->child = input->child->Accept(this); */
return input;
}
virtual Type* Handle(Type2* input) { return input; }
};


struct DumpAction : TypeVisitor
{
virtual Type* Handle(Type1* input) override
{
std::cout << "Handling type 1." << std::endl;
return TypeVisitor::Handle(input);
}

virtual Type* Handle(Type2* input) override
{
std::cout << "Handling type 2." << std::endl;
return TypeVisitor::Handle(input);
}
};

int main()
{
DumpAction act;
Type2 type2;
type2.Accept(act);

return 0;
}

关于c++ - 如何根据参数的类型实例化不同的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43362744/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com