【问题标题】:Storing list of names associated with tasks存储与任务关联的名称列表
【发布时间】:2018-12-18 15:35:01
【问题描述】:

所以我已经制作了这个任务系统,或者我正在尝试制作它,这样如果有人完成了七项以上的任务,那么下一个人必须完成七项。

双打(Bodine、Finn、Tycho)是人。现在我不知道我是否正确使用它,(如果它们需要双打)以及我如何在这行代码中使用它们:

if (taskNumbers == 7)
{
    std::cout << "It's " + /*what to do here? */ + "time!";

我想要的是,如果任务数量高于 7,并且 Bodine 已经完成了 7 个任务,它会说“It finn his time!”

#include <iostream>

using namespace std;

double Bodine;
double Finn;
double Tycho;
bool tasksDone = true;
int taskNumbers = 0;

int main()
{
  if (taskNumbers > 7)
  {
    std::cout << "It's " + /*what to do here? */ + "time!";
    return 1;
  }
}

这是我的第一个项目之一(我 13 岁,所以是的....)。我只需要知道如何使用下一个变量!

【问题讨论】:

  • 从您的问题中不清楚这里的目标是什么。任务是如何记录的?您如何在程序运行之间保存这些信息?这是定义的方式,taskNumbers 是并且永远都是零。
  • 我刚刚编辑了它,我的问题是我如何使用下一个变量,如果我需要在这种情况下使用双精度数
  • 虽然 C++ 几乎可以教给任何人,但它比其他人学习起来更加微妙和棘手。您可能希望从 Python、Ruby 或 JavaScript 等更宽容的东西开始,以了解编程的一般工作原理,然后再深入研究 C++ 之类的东西,它具有其他层,如编译、链接、强类型等开。
  • 这是一个很大的如果。除非您有一位非常了解 C++ 的导师,否则这可能是一条非常艰难的道路。 C++ 是极其无情的,如果你犯了一个小错误,你的程序就会突然崩溃或表现得非常奇怪,从而导致数小时的令人沮丧的调试。那是假设它首先编译,这也可能很难解决。我并不是说你不能学习 C++,但作为一种“第一”语言,它是一个相当大的挑战。
  • C++ 中没有“下一个变量”的概念(或据我所知的任何其他语言)。您正在努力的是数据结构的概念,它定义了模拟中人员的顺序。为此,简单的选择是人员向量和指示当前人员身份的变量。

标签: c++ variables


【解决方案1】:

嗯,你并没有真正跟踪轮到谁了。此外,double 不是适合这里工作的工具。我会这样做:

std::vector<std::string> users = { "Bodine", "Finn", "Tycho" };
int currentUser = 0;

现在我们有一个名字列表和一个计数器,显示轮到谁了。 0 用于第一人称,1 用于第二人称,2 用于第三人称。然后我们需要推进那个计数器的逻辑:

void advanceUser() {
    if (++currentUser >= users.size()) {
    currentUser = 0;
    }
}

这增加了currentUser,当它大于人数时,它循环回到0,所以人们轮流正确。

接下来关于任务逻辑,我建议如下:

int tasksDone = 0;
void incrementTasksDone() {
    if (++tasksDone >= 7) {
        advanceUser();
        std::cout << "It's " + users[currentUser] +"'s time!" << std::endl;
        tasksDone = 0;
    }
}

这里我们有一个计数器来跟踪任务的数量,当它到达7 时,它会将其设置回0,并在调用advanceUser 进行设置后宣布轮到下一个用户了.

然后你可以随意拨打incrementTasksDone,例如我这样测试过:

int main()
{
    for (int i = 0; i < 100; i++) {
        incrementTasksDone();
    }
}

例如,这将完成 100 个任务,因此轮数会在此过程中更改 14 次,并且每次都会打印消息。

此外,要运行此示例,请务必添加以下内容:

#include <vector>
#include <string>
#include <iostream>

【讨论】:

  • 在编译之前需要一些#include的爱,但这里有很好的例子。
  • 我有种忘记了什么的感觉。 :) 现在添加了包含。
  • 你确定要在 if (++currentUser >= users.size()) 中使用吗,你需要 >= 而不仅仅是 > 因为我想在他们都完成任务后将其循环回来
  • @Rohan 是的,因为索引从 0 开始。有三个名称和三个数字(0、1、2)
  • 虽然还有一个问题... V
【解决方案2】:

您好,欢迎使用 C++。许多人会说 C++ 对于初学者来说是一种糟糕的选择语言。好吧,我很久以前就开始使用 C++,直到今天我还在学习。我是 100% 自学成才的,我不具备当今人们在互联网上提供的大量信息以及可用的现代格式方面的优势。当我刚开始学习 C++ 时,互联网正处于蓬勃发展的阶段;但当时大多数网站几乎都是纯文本,即使是简单的图片或图形也需要一段时间才能加载到屏幕上,因为那是在Dial Up 的时代。今天,刚起步的人拥有这个网站、其他类似网站甚至 youtube 视频的优势。但是,我仍然喜欢尽我所能提供帮助,因为它不仅可以帮助您,还可以帮助我改进我已经学到的知识。 C++ 多年来一直在发展,所以我将在这里向您展示一个小型应用程序,我相信它模仿了您所描述的您正在尝试做的事情的行为。其中一些技术对于初学者来说有点先进,但是我认为新手早期学习这些概念是一个很好的选择。


  • Storage Types &amp; Lifetime - C++ 中基本上有 4 种主要存储类型:AutomaticDynamicStaticThread。我主要关注前 3 个。

    • Automatic: 它具有声明它的范围的生命周期,并且一旦该范围退出其右括号},它将自动被销毁
    • Dynamic: 由指针表示但用new 声明的内存,并且必须分别具有匹配的delete 或数组new[]delete[]。它们的寿命可以比声明它们​​的范围更长。它们将一直存在,直到调用匹配的 delete 为止。如果没有匹配的删除发生,这会导致内存泄漏、无效指针、悬空指针和引用以及未定义的行为。使用raw-pointers时需要特别小心;建议使用containerssmart pointers
    • Static: 这些通常位于global 命名空间和/或global filespace。如果在main.cpp 中声明了static,它将具有应用程序的生命周期和整个程序的范围。如果它们在其他 cpp 文件中声明,它们将具有该文件的范围,除非它们在某些 header 文件中声明,那么它们将具有其他翻译单元包含该标头的范围。它们类似于Automatic,因为它们会被自动销毁,但它们的不同之处在于它们只被初始化一次,保持它们的状态并且你只能拥有它们的一个实例。
    • 有关不同类型存储分类的演示,您可以查看我之前对此Q/A 的回答。
  • Classes and Inheritance: - (我不会涉及Polymorphism)。

    • Classes:
      • ClassesStructs 是用户定义的数据类型。
      • 两者的区别在于默认访问
      • 默认情况下:StructsPublic Members & ClassesPrivate Members
      • ClassStruct 的成员可以是任何内置类型、指向类型的指针、其他用户定义的数据类型以及方法或函数。
      • Member Variables 可以是任何Storage TypeAutomaticDynamicStaticThread,但是,成员函数通常是Automatic,但也可以是Static。如果您有 member variable,则它必须是 initialized 之外的 Class's Declaration 才能解析为 symbols
      • 默认情况下他们有ConstructorsDestructors,但可以创建自己的自定义ConstructorDestructor。您通常会看到人们通过他们的简称提及他们:ctordtor
      • 一个类可以继承另一个类。
    • Inheritance:
      • 你有BaseSuperClasses,你有DerivedChildClasses
      • Inheriting 来自Base 类时,如果Base 类的ctorPublic,这意味着您可以创建BaseDerived Classes 的对象。有时您想要这种设计,但有时您不想要。
      • 如果您不希望用户能够创建 Base Class 的实例,但能够创建 Derived Class 的实例,那么您需要做的就是确保 1st 它的ctorProtected。如果你声明它Private,那么即使你的Derived Classes 也不能访问它,因此它们不能被声明。 *2nd 你要确保你的Destructors - dtorsVirtual;否则你会遇到销毁类的顺序问题。
      • 一个Base Class 可以有Member FunctionsVirtual 这意味着所有Derived Classes 必须Implement 那个Function
      • Base Class 可以有 Member FunctionsPurely Virtual,这与上面类似,但也阻止任何人声明此 Base Class 的实例,因为这使得 Base @987654422 @Abstract 这意味着这是一个界面的想法。
      • 示例VirtualFunction:virtual update();
      • 例如Purely Virtual:`virtual update() = 0;
  • Containers - (我将使用std::container,但我不会涉及任何Algorithms

    • 容器种类繁多,满足不同需求;这些容器有助于使您的程序保持简单、易于管理和调试、用户友好,并避免使用basic C Arrays 来避免许多未来的麻烦。
    • 有几种不同的类型,它们都有自己的用途和属性,我不会详细介绍它们的所有细节,因为您可以在网上找到大量关于它们的信息,但我会将它们标记并分组到它们的相似属性:分组为Sequence ContainersAssociative ContainersUnordered Containers,这些都属于std::namespace。分组之间的主要区别是:Sequence Containers 类似于arrayslinked listsAssociative Containers 类似于binary trees,而Unordered Containers 类似于binary trees,只是它们不按顺序排列,它们被认为是hash tables
      • Sequence: vector, dequeue, queue, list, forward_list, array
      • Associative: set, multiset, map, multimap
      • Unordered: unordered_set, unordered_multiset, unordered_map, unordered_multimap`
    • 这些容器的强大之处在于能够快速遍历它们或根据您使用的容器快速插入和查找。另一个很好的功能是在内存管理过程中提供帮助。最后是无数的 algorithmsiterators 可以对它们进行处理。
    • 有关stl 的更多信息,我建议观看this youtube 系列Bo Qian
  • Smart Pointers 有几种不同的类型,但最重要的两个是std::shared_ptr&lt;T&gt;std::unique_ptr&lt;T&gt;。两者的主要区别在于shared 有一个reference count 来表示有多少对象可以访问它;这意味着它具有公共类型接口并且可以使用复制语义;另一方面,unique 一次只有1 owner,它可以转让所有权,但一旦转让,原所有者就不再有权访问它。您不能复制unique,但可以移动它们。这些智能指针有助于使用dynamic memory 和生命周期对象管理,以防止内存泄漏、无效指针、悬空指针和引用、未定义行为等。它们有助于最大限度地减少newdelete 和@987654477 的使用@ & delete[] 分别。


现在您已经了解了在C++ 程序中经常看到的一些概念;现在,我将向您展示我根据我认为您正在尝试做的事情编写的简单应用程序:

#include <array>
#include <exception>
#include <memory>
#include <string>
#include <iostream>  

class Person {
protected:      
    std::string name_;
    int tasksCompleted_;
public:
    const std::string& whoIs() const { return name_; }
    int numberTasksCompleted() const { return tasksCompleted_; }

    virtual void performTask() = 0;

protected:
    explicit Person(const std::string& name) : name_{ std::move(name) } {}
    virtual ~Person() = default;
};

class Bodine final : public Person {
private:
    static int currentTask;
public:
    explicit Bodine(const std::string& name = std::string("Bodine")) : Person(name) {}
    virtual ~Bodine() = default;

    virtual void performTask() { currentTask++; tasksCompleted_ = currentTask;  }
};
int Bodine::currentTask = 0;

class Finn final : public Person {
private:
    static int currentTask;
public:
    explicit Finn(const std::string& name = std::string("Finn")) : Person(name) {}
    virtual ~Finn() = default;

    virtual void performTask() { currentTask++; tasksCompleted_ = currentTask; }
};
int Finn::currentTask = 0;

class Tycho final : public Person {
private:
    static int currentTask;
public:
    explicit Tycho(const std::string& name = std::string("Tycho")) : Person(name) {}
    virtual ~Tycho() = default;

    virtual void performTask() { currentTask++; tasksCompleted_ = currentTask; }
};
int Tycho::currentTask = 0;

int main() {
    try {
        std::array<std::shared_ptr<Person>, 3> people{
            std::shared_ptr<Person>(new Bodine()),
            std::shared_ptr<Person>(new Finn()),
            std::shared_ptr<Person>(new Tycho())
        };

        // For each person in array
        const int MAX_TASKS = 7;
        int currentPerson = 0;
        for (auto& p : people) {
            std::cout << p->whoIs() << " has performed task #:\n";
            while (p->numberTasksCompleted() < 7) {
                p->performTask();
                std::cout << p->numberTasksCompleted() << '\n';
                if (p->numberTasksCompleted() == MAX_TASKS) {
                   currentPerson++;
                   if (currentPerson <= (people.size() - 1) ) {
                       std::cout << "It's your turn " << people[currentPerson]->whoIs() << " to do some tasks.\n";
                   }
                   break;
                }
            }
        }

    } catch( std::runtime_error& e ) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;    
}

-输出-

Bodine has performed task #:
1
2
3
4
5
6
7
Finn has performed task #:
1
2
3
4
5
6
7
Tycho has performed task #:
1
2
3
4
5
6
7

Link 以上程序。


我知道这有点难读;但请仔细查看应用程序以尝试查看它在做什么。您可以将其复制并粘贴到您自己的 IDE 中,然后尝试构建并运行它以查看它的实际效果。希望这能让您了解C++ 是什么。


-编辑-

关于上面的代码:它比它真正需要的要复杂一些。首先,您不会真正将单个人的身份视为自己的班级。我这样做只是为了演示inheritance 是什么。我选择使用std::array 而不是std::vector 主要是因为您的提案中有3 特定人员。如果您在编译时有未知数量的人,那么std::vector 将是正确使用的容器。您也不需要使用继承。此外,如果您查看3 派生的classes,则有很多duplicate 代码。我还使用了shared_ptrs 来展示如何使用它们,但在您的特定情况下不是必需的。我还在Derived Classes 中使用了static member variables 来显示static storage

这是上述代码的简化版本,用于模仿您的行为。两个程序执行相同的任务,唯一的主要区别是:inheritancepurely virtual methodsstatic member storagecontainer typedynamic memory 的使用通过使用 shared_ptr

#include <exception>
#include <iostream>
#include <string>
#include <vector>    

class Person {
private:    
    std::string name_;
    int tasksCompleted_;
public:
    explicit Person(const std::string& name) : name_(name), tasksCompleted_(0) {}

    const std::string& whoIs() const { return name_; }
    int numberTasksCompleted() const { return tasksCompleted_; }

    void performTask() { tasksCompleted_++; }
};

int main() {
    try {
        std::vector<Person> people{
            Person( "Bodine" ),
            Person( "Finn" ),
            Person( "Tycho" )
        };

        // For each person in array
        const int MAX_TASKS = 7; // Don't like magic numbers!        
        int currentPerson = 0; // Needed variable
        for (auto& p : people) {
            std::cout << p.whoIs() << " has performed task #:\n";
            while (p.numberTasksCompleted() < MAX_TASKS) {
                p.performTask();
                std::cout << p.numberTasksCompleted() << '\n';
                if (p.numberTasksCompleted() == MAX_TASKS) {
                   currentPerson++;
                   if (currentPerson <= (people.size() - 1) ) {
                       std::cout << "It's your turn " << people[currentPerson].whoIs() << " to do some tasks.\n";
                   }
                   break;
                }
            }
        }

    } catch( std::runtime_error& e ) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;    
}

这是此版本程序的link

【讨论】:

  • 我认为我的 c++ 版本太旧了...无法运行
  • 您的项目使用什么 IDE?
  • @Rohan 我使用 Visual Studio 2017 社区版,我将语言设置设置为 C++17newest standard draft
  • 这些都是你自己教的吗?你只是测试一下吗?或者您正在搜索网络,查看在线教程?因为我会说你是专业人士!
  • 关于你的代码,我更多的是在寻找一个在 7 个任务之后显示的程序,好吧,现在轮到你了,你知道吗?
猜你喜欢
  • 1970-01-01
  • 2014-12-06
  • 1970-01-01
  • 1970-01-01
  • 2011-05-01
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多