【问题标题】:Is there a way to declare objects within a conditional statement?有没有办法在条件语句中声明对象?
【发布时间】:2019-06-21 14:24:53
【问题描述】:

根据用户的选择,我无法弄清楚如何正确创建对象。

在程序中,我问用户他们想成为哪个职业——骑士或巫师。我输入“1”或“2”来代表骑士和巫师。

我做了一个 switch 语句,在案例 1 中,我声明了一个对象骑士,巫师也是如此。

我需要在 switch 语句之外使用这些对象,但我不能。我试图通过制作“玩家播放器”来制作“默认”对象;但是因为 Player 类有一个纯虚函数,我也做不到。

我如何有效地做到这一点?

这是我目前所拥有的:

int main()
{
std::string plyrName;
int input;
bool foo = false;

std::cout << "What is your name?\n";
std::cin >> plyrName;
std::cin.ignore(1000, '\n');

std::cout << "\nWelcome, " << plyrName << ". What class would you like to be?\n";
std::cout << "1. Knight.\n2. Wizard.\n";
std::cin >> input;

while (input != 1 && input != 2)
{
    if (foo == true)
        std::cout << "Please enter 1 for Knight and 2 for Wizard.\n";
    if (!(std::cin >> input))
    {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "\n";
        std::cout << "Only integers are allowed.\n";
    }
    else
        std::cout << "\n";
    foo = true;
}

switch (input)
{
case 1:
{
    Wizard player;
    break;
}
case 2:
{
    Knight player;
    break;
}
}


std::cout << "\nHere is your player information summary.\n";
std::cout << player.classType();

system("pause");
return 0;
}

我需要在创建后访问播放器对象,因为我想向用户输出他们选择的类。 Knight 和 Wizard 类都有输出这个的函数。

编辑:我有一个后续问题。在图中,Knight & Wizard 有一个静态变量“特殊攻击名称”。如何在主函数中访问此变量?使用 unique_ptr 的解决方案意味着指针将指向基类 Player,因此不允许访问派生类成员,例如静态变量“特殊攻击名称”。我的设计有缺陷吗?

【问题讨论】:

  • 也许使用指针(最好是smart pointers)?这就是您通常在 C++ 中处理多态性的方式。
  • 如果你想使用多态性,无论如何你都需要指针或引用,也许先解决这个问题,因为从字面上回答你的问题只会把你带到下一个问题
  • @user463035818 “先解决这个问题”是什么意思,回答这个问题会导致下一个问题?如果我想使用多态性并防止导致另一个问题,我将如何解决这个问题?
  • 我的意思是,可以从字面上理解您的问题并编写一个“解决方案”来创建 KnightWizard 对象,但这不会帮助您将它们都视为 @ 987654326@ 除非您使用指针或引用。请注意,答案已经考虑到了这一点(准确地说是三分之二;)

标签: c++ object if-statement


【解决方案1】:

在你的情况下,因为你想完成多态,你应该去指针和引用。为什么?我强烈推荐这个美丽的答案。 Why doesn't polymorphism work without pointers/references?

那么,您是否应该使用原始指针,例如 Player *

在几乎所有情况下,您都不应该使用原始指针,尤其是当它指向动态内存时。仅仅是因为任何编程错误或异常都可能导致delete 被跳过。

因此,我强烈建议您使用 C++11 中引入的智能指针,例如 unique_ptrshared_ptr,它们遵循 RAII 模式并保证取消初始化。

这是您的情况下使用unique_ptr 的示例。

#include <memory>

using PlayerPtr = std::unique_ptr<Player>;
using KnightPtr = std::unique_ptr<Knight>;
using WizardPtr = std::unique_ptr<Wizard>;

int main()
{
    ...
    PlayerPtr playerPtr = nullptr;

    switch (input) {
        case 1: {
             playerPtr = KnightPtr(new Knight);
        }
        break;

        case 2: {
             playerPtr = WizardPtr(new Wizard);
        }
        break;
    }

    // use playerPtr outside.
}

编辑:

正如HTNW 正确指出的那样,您必须使用std::make_unique 而不是使用new。但请记住,这是一个 C++14 概念。你必须有它的编译器支持。

【讨论】:

  • 谢谢你!一般来说,这是一种有效的方法吗?或者,如果我刚开始制作这些程序,我应该以完全不同的结构来完成吗?
  • 这个答案如果recommended using std::make_unique over new 会更好,并解释了为什么我们需要使用指针。
  • 我认为您应该采用工厂模式,而不是使用开关盒。从长远来看,它将对您有所帮助。
  • @HTNW 我试图改进我的答案。希望它看起来比以前的要好得多。
  • @KunalPuri 因为 switch 语句不是工厂的实际实现?
【解决方案2】:

如果您在 switch case 范围内创建变量,它将在您离开该范围导致您进入 UB 时立即被删除,因此您将其声明为指针,以便它可以超过条件语句,即:您将其声明为基础在&之前的类指针,您将其指定给它在条件语句中指向的位置

#include<memory>
int main()
{
std::string plyrName;
int input;
bool foo = false;
//create your player ptr
std::unique_ptr<Game_Object> player;
std::cout << "What is your name?\n";
std::cin >> plyrName;
std::cin.ignore(1000, '\n');

std::cout << "\nWelcome, " << plyrName << ". What class would you like to be?\n";
std::cout << "1. Knight.\n2. Wizard.\n";
std::cin >> input;

while (input != 1 && input != 2)
{
    if (foo == true)
        std::cout << "Please enter 1 for Knight and 2 for Wizard.\n";
    if (!(std::cin >> input))
    {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "\n";
        std::cout << "Only integers are allowed.\n";
    }
    else
        std::cout << "\n";
    foo = true;
}

switch (input)
{
case 1:
{   // initialize it  and it would work perfectly as you intend
    player = std::make_unique<WIZARD>();
    break;
}
case 2:
{   //****
    player = std::make_unique<KNIGHT>();
    break;
}
}


std::cout << "\nHere is your player information summary.\n";
std::cout << player->classType();

system("pause");
return 0;
}

【讨论】:

  • 请解释您的解决方案,而不是仅仅转储一些代码!
【解决方案3】:

如果我错了,请有人纠正我,但对象仅在它们创建的范围内有效,因此一旦您退出该 switch 语句,这些对象就无法再访问了。

您应该在 switch 语句之外声明一个 GAME OBJECT 类对象,然后创建向导或骑士(因为这两个类都继承了 GAME OBJECT)。

【讨论】:

  • 局部变量确实如此,但是使用分配器(使用关键字'new')获得的内存(变量)将持续到它们被显式释放。为了简化这些分配变量的使用,C++11 标准引入了智能指针。
  • 回复:“如果我错了,请纠正我”——你说对了一半。 命名 对象具有块范围;它们在创建它们的块的末尾消失。您的解决方案不太正确。您需要创建一个指向GAME_OBJECT指针,并创建一个WIZARDKNIGHT 并将其地址存储在该指针中。该对象不能是命名对象,因为那样它就会消失。这就是为什么我们有new
  • 阅读“对象切片”,你写的几乎是正确的,它只是不适用于对象
猜你喜欢
  • 1970-01-01
  • 2012-03-23
  • 2014-04-10
  • 1970-01-01
  • 2020-07-31
  • 1970-01-01
  • 1970-01-01
  • 2020-07-16
  • 1970-01-01
相关资源
最近更新 更多