【问题标题】:Is it possible to reference random classes?是否可以引用随机类?
【发布时间】:2013-10-16 00:17:20
【问题描述】:

有没有办法让用户输入引用随机类实例?我的意思是基于已经创建的那些?有点像一个开关,但没有写出开关内的每个实例?我希望我的代码更加通用,以便其他人可以在不更改开关或代码其他部分的情况下添加代码。

我知道帖子的组织方式有点曲折,但我觉得这是整理帖子想法的最佳方式,所以请多多包涵。在最底部的代码中,我创建了一个指针来更改“test1”实例中的变量。我希望能够让程序能够获取用户输入来选择哪个类,然后在那里进行更改。我知道这种语法不起作用,但例如:

class test {
public:
    int number;
    int letter;
}
test classTest; //to get user input of which class he wants to select
                //to change a variable
cin >> classTest; //user inputs choice
test * classPointer; //pointer to variables
cin >> classPointer -> number;
cin >> classPointer -> letter;
//where classTest is actually not a normal instance, just a way to get user
//input to select which class instance variables he'd like to change

这里是我的问题开始和这个问题源于的一点背景。如果您不关心它/需要它来回答我,您可以跳过它。我正在编写一个 RPG 游戏来练习我在 C++ 中所学的内容,并且我想让我编写的代码相当通用。例如,如果我有一个类可以创建某些在“城镇”中通用的对象。比如物品商店、旅馆等。在战斗系统中你可以选择使用物品。在该项目类别中,应该只列出可用的项目。没问题,我可以写大量的 if 和开关和布尔值——但是我不想为战斗系统中的每个项目都写所有这些,我想要某种机制来为我做到这一点。我相信如何调用指针的一些技巧将解决我的问题。但是,说了这么多,请不要被我的背景故事所牵扯。它只是为了帮助您了解我的思维过程,如果它不能解决这个问题,就这样吧,无论如何我都需要知道这些信息以供参考。

#include <iostream>
#include <stdio.h>

class test {
public:
    int number;
    char letter;
    void function() {
        printf("Number = %d\nLetter = %c", number, letter);
    }
    test() {}
    test(int a, char b) : number(a), letter(b) {}
};

int main()
{
    test* pointer;
    test test1(1, 'c');
    pointer = &test1;
    test1.function(); //output initial result
    printf("\nEnter a new number: ");
    std::cin >> pointer -> number; //change number
    printf("Enter a new letter: ");
    std::cin >> pointer -> letter; //change letter
    test1.function(); //output changed result
    return 0;
}

【问题讨论】:

  • 您需要创建某种查找表,以某种方式将字符串映射到类。如果你可以使用 C++11 的 lambda 特性,你可能会以一种相当干净的方式做到这一点,否则你需要函数指针。
  • 我完全不明白为什么你将test* pointertest test1 视为基本相同的东西。如果需要指针,请使用 new 分配器,否则使用基于堆栈的实例。两者都用没有多大意义。
  • @tadman 这就是我学会使用指针的方式。我没有意识到实例 test1 与该程序中的指针几乎相同。你能详细说明你的意思吗?如果这意味着什么,我写了 pointer = &test1 作为一个例子。我真正想要的不是 &test1 而是 &userInput。
  • 听起来像是基本的多态性。这些类是否需要在运行时可扩展,例如应用程序插件?如果是这样,您需要一个工厂模式来创建与提供的基本类型兼容的对象。如果没有,那么您仍然可以使用相同的模式,但它会变得更容易。即使我只有两种类型,我仍然更喜欢通过基类指针或引用而不是条件的多态行为。让 vtable 成为你的 switch 语句。
  • 通常你有类似 test* p = new test(...)test s(...) 的东西,你想要一个明确的指针,你打算在本地范围之外使用它,或者你不在乎和一个堆栈-分配的对象很好。调用p-&gt;fn()s.fn() 相同。为了有效地学习 C++,您需要知道何时需要指针,以及如何分配此分配的“所有权”,何时可以使用“拥有”它的容器类,以及何时使用堆栈分配的本地.为不同的变量混合使用指针、引用和局部变量,但要与你对任何一件事的方法保持一致。

标签: c++ class pointers reference


【解决方案1】:

我对代码 sn-ps 和密密麻麻的文字有点迷惑,但你描述的这种问题是相当普遍的。

要创建基于某个键的类型的对象,您可能希望将抽象工厂模式作为您的起点 - 在您附近的所有优秀教科书和更有信誉的 wiki 中都可以找到。如果它看起来对您的目的来说过于夸张,请不要犹豫 - 就像所有模式一样,您可以将其剪裁以满足您的需求。

本质上,对于您想要创建的每种类型的对象,您都需要一个知道如何制作它的工厂。制作此相关对象集合所需的所有工厂都应共享相同的接口。

要选择正确的工厂来创建请求的对象类,您需要持有一个键映射,即工厂的字符串。该地图取代了您可能想使用的 if-else/switches。如果您想尽量减少打字并混淆您的敌人和朋友,可以使用 Singleton 来针对密钥注册工厂,但请先阅读所有健康警告:

// 城镇中所有住宅的基类 类住宅 { 上市: 虚拟〜住宅(){} 虚拟住宅(整数,字符字母); 虚拟 Enter() = 0; 虚拟离开()= 0; // ... 无论您在城镇住宅中可以做什么其他常见的事情 */ }; // 一种住宅 - 随心所欲 类商店:公共住宅 { virtual Shop(int number, char letter) : 住宅(数字、字母) { /* 东西 */} 虚拟回车(); 虚拟离开(); }; // 用于制作住宅类型的基础工厂类 类 AbstractDwellingFactory { 上市: 虚拟 DwellingFactory() {} 虚拟住宅 * Create(int number, char letter) = 0; }; // 所有住宅工厂的收集和注册 - 一个 Meyer's Singleton 方便起见 类 DwellingFactory { 上市: 静态 DwellingFactory & Instance() { static DwellingFactory theInstance; 返回实例; } // 根据给定的类型和其他参数创建住宅 - 考虑智能指针而不是此处显示的原始指针 住宅 * 创建(std::string const & 住宅住宅类型,整数,字符字母) { // 假设我们有一个匹配的工厂,让我们成为一个住宅。 // 显然,在现实世界中这里需要一些错误检查 return myAbstractDwellingFactoryMap[dwellingType].Create(number, letter); } 无效寄存器(std::strinf 常量和住宅类型,AbstractDwellingFactory 常量和事实) { myAbstractDwellingFactory[dwellingType] = &fact; } 私人的: 住宅工厂(){} // 类型映射的实际键 std::map myAbstractDwellingFactoryMap; }; // 一个通用的混凝土工厂 模板 类 ConcreteDwellingFactory : 公共 AbstractDwellingFactory { 上市: ConcreteDwellingFactory(std::string const &dwellingType) { DwellingFactory::Instance().Register(dwellingType, *this); } // 工厂函数 - 注意我们可以在这里返回一个指向派生类型的指针 - 查找“co variant return types” DwellingType * Create(int number, char letter) { 返回新的住宅类型; } }; // 您要支持的每种住宅类型的工厂实例 static ConcreteDwellingFactory shopFactory("Shop"); 无效的一些函数() { std::string 住宅类型; 整数; 字符字母; std::cin >> 住宅类型 >> 数字 >> 字母; 住宅 *requestedDwelling(DwellingFactory::Instance().Create(dwellingType, number, letter)); 请求住宅->输入(); // 等等 }

【讨论】:

  • 现在我的城镇实际上是类的实例。比如... town Frosttown(1,0,1) //有一家旅馆,没有商店,有一个可以交谈的人.. 当我移动到世界地图上的某些位置时,它会调用 .options(); // 是输入的实际城镇。 options 函数查看构造函数中设置的参数和包括全局变量在内的其他几个变量,以拼凑在城镇实例中要做什么。从您的帖子看来,我想避免这种情况并让城镇继承基类城镇的类?与物品类等一样吗?
  • 是的,如果有不同类型的城镇,可以共享同一个base,根据需要实现options()。如果一个城镇完全由它包含的项目(或住宅)定义,那么它可能是一个简单的类,包含一组在建设中确定的项目。从一组物品建造特定城镇的过程可以转移到一个单独的工厂。听起来您可能可以使用某种表格来描述各个城镇所包含的内容,而不是为每个变体编写单独的类。
  • 像我的问题中提到的那样的表格?或者在 Boost 或 STL 中有什么东西?
  • @Scott 在上面的 cmets 中提到是“某种查找表,它以某种方式将字符串映射到类”。这可以通过对有限数量的类使用 boost::fusion 库来实现,或者有一些方法可以为任意数量的类手动滚动它。这不是我的建议
  • 我的意思是,您的城镇可以由根据表(或一组链接表)中保存的配方构建的有限数量类的多个对象构建。这样的表可以是简单的结构数组、由初始化列表 (C++11) 制成的容器,也可以是从 XML 文件甚至数据库中读取的容器。
猜你喜欢
  • 2021-04-08
  • 1970-01-01
  • 2013-11-30
  • 2021-04-09
  • 1970-01-01
  • 2017-09-19
  • 1970-01-01
  • 2017-03-20
  • 2014-12-31
相关资源
最近更新 更多