使用类和函数来跟踪用户统计信息

Posted

技术标签:

【中文标题】使用类和函数来跟踪用户统计信息【英文标题】:Using a class and functions to keep track of user stats 【发布时间】:2020-12-07 19:59:15 【问题描述】:

我是 C++ 新手,想知道我做错了什么。

我正在尝试创建一个基于文本的冒险游戏,该游戏使用添加或删除功能来跟踪玩家统计数据。目前,我的函数没有为 trust 添加五个点,我正在努力做到这一点。

#include "function.h"
using namespace std;

int main() 
    double trust=100;
    editPlayer user(100);
    //asks user choice
    cin >> firstChoice;
    if (firstChoice == 1) 
        user.addTrust(trust);
        cout << trust;

这是我的function.cpp,仅以信任为例:

#include "function.h"

editPlayer::editPlayer(double trust) 


void editPlayer::addTrust(double trust)
    trust +=5;


void editPlayer::removeTrust(double trust)
    trust -=5;

这是我的function.h

#include<iostream>
#include<string>
using namespace std;

class editPlayer
public:
    editPlayer(double trust);
    void addTrust(double);
    void removeTrust(double);
;

【问题讨论】:

你用哪本书来学习C++?这不是类的使用方式。 【参考方案1】:

让我们使用你的addTrust 函数:

void editPlayer::addTrust(double trust) 
    trust += 5;

这将修改局部变量trust,然后函数将结束。当函数结束时,局部变量trust的生命周期也结束了,你对它所做的修改也会丢失。

如果你真的想修改参数,你需要通过引用传递它:

void editPlayer::addTrust(double& trust) 
    trust += 5;

或者返回新值:

double editPlayer::addTrust(double trust) 
    return trust + 5;

如果返回新值,需要在调用函数时赋值给它:

trust = user.addTrust(trust);

如上所述,代码和editPlayer 类没有多大意义。真的不需要editUser 的课程。 addTrust 可能是一个非成员函数,或者根本不是一个函数。

类名没有意义,因为它不会“编辑”任何东西。并且将参数传递给构造函数也没有意义,因为对象没有任何内部状态(传递给构造函数的值只是被丢弃)。

【讨论】:

【参考方案2】:

目前,您没有代表 user 对象(editPlayer 类的对象。

cout &lt;&lt; trust; 语句仅打印您在开头声明的 trust 局部变量的值:double trust=100;。因为这个变量自初始化以来一直没有改变,它仍然等于 100,这就是你所看到的。

为了跟踪任何editPlayer 特定的信息,最好的办法是将这些信息存储作为editPlayer 类的数据成员。您可以像这样声明一个表示对象的信任的数据成员:

class editPlayer
public:
    editPlayer(double trust);
    void addTrust(double);
    void removeTrust(double);
    double getTrust() const;  // add also this one, will be useful
private:
    double m_trust 0;   // <---- here - a data member, aka. a class field
;

现在你必须改进你的构造函数,让它利用它所接受的参数并将它的值分配给这个新的数据成员(因为目前构造函数什么都不做):

editPlayer::editPlayer(double trust) 
    m_trust = trust;

现在在成员函数中,您已经重命名了变量,以便它反映 trust 数据成员(而不是参数),这将有效地允许更新其值:

void editPlayer::addTrust(double trust) 
    m_trust += 5;


void editPlayer::removeTrust(double trust) 
    m_trust -= 5;


double editPlayer::getTrust() const   // add definition of our "getter"
    return m_trust;

最后,您可以使用生成 m_trust 值的 getter 调用替换我们已经讨论过的 cout &lt;&lt; trust;(仍然打印局部变量的值):

cout << user.getTrust();

并查看执行addTrust() 操作的实际效果,并对您的合法面向对象程序感到满意。

【讨论】:

【参考方案3】:

一般来说,您所询问的代码可以被类、成员声明以及一些面向对象编程所覆盖。 如果您搜索它,互联网上有很多好的(和不太好的)教程。

我会在以下搜索中试试运气

CPP + 课程 CPP + 成员声明 CPP + 动态与静态内存分配(指针和东西) 面向对象编程 (OOP)

本网站上的示例提供了很多基本概念恕我直言的好(和短 :D)示例。 https://www.tutorialspoint.com/cplusplus/cpp_classes_objects.htm

其中一些主题也适用于其他语言。


我的 cmets 的第一个块:

#include "function.h"
using namespace std; // dont get into the habbit of using namespace std;
// the above can potentially open up for bugs

int main() 

  double trust=100; // This variable is declared in this scope( ... )
  // and will get deallocated once the scope ends with the character ''
  editPlayer user(100); // instance of editPlayer named 'user' is constructed
  //asks user choice
  cin >> firstChoice;
  if (firstChoice == 1) 
    user.addTrust(trust); // calling function on user object
    cout << trust;

现在查看 .h 文件,我主张不要在标头中包含您不使用的标头。 对于小型项目,这根本不重要 - 但对于包含数千行代码的大型项目,删除未使用的包含可以加快速度。

有些人更喜欢前向声明 - 一旦您对 cpp 的基础知识更加熟悉,就可以研究一下。

#include<iostream> // not used here
#include<string> // not used
using namespace std; // disaster waiting to happen

class editPlayer
public:
    editPlayer(double trust);
    void addTrust(double);
    void removeTrust(double);
;

.cpp 文件

#include "function.h"
editPlayer::editPlayer(double trust) 

// function implementation with argument - but argument is not used - change to void fun(double) -> fun(void) OR fun()
void editPlayer::addTrust(double trust)  trust +=5; 

void editPlayer::removeTrust(double trust)  trust -=5; 

我做了一个类声明和成员变量的例子。

#include <iostream>
#include <string>

// this is a class declaration
class Player

protected: // protected member variables
    double _trust;
public: // public interface
    Player(double trust);
    void addTrust(double);
    void removeTrust(double);

    double getTrust() const;
;

// Implementation of public interface
// notice _trust is the member defined in the class
Player::Player(double trust) : _trust(trust)  // constructor

// example of default parameters (do note that only definition or declaration can have them)
// This means that calling the function without arguments will become 5
void Player::addTrust(double trust = 5)  _trust += trust; 
void Player::removeTrust(double trust = 5)  _trust -= trust; 
double Player::getTrust() const return _trust; 

int main() 

    Player player(100); // this will invoke the constructor - and the player object will get initialised with the given state

    std::cout << player.getTrust() << std::endl;

    // variable to buffer input data into - assuming type int wrt. following if
    int firstChoice;
    //asks user choice
    std::cin >> firstChoice;
    if (firstChoice == 1) 
    
        player.addTrust(25);
        player.addTrust();
    
    std::cout << player.getTrust();

编码愉快!

【讨论】:

const double getTrust(); - const 在返回的类型之前添加 按值 是无用的。可能你的意思是把这个 const 说明符放在 声明之后,使其成为 const 成员函数double getTrust() const;. @bloody 是的,或者将其设为 const ref @bloody 我做了这个实验——当返回类型为 const double& getTrust();成员变量仍然不是 const。我尝试运行以下几行 -> 首先是复制分配 double d = player.getTrust(); d += 1.0; 在没有 const 的情况下进行引用会产生编译错误。增加 const double const double &amp;cd = player.getTrust(); cd += 1.0; 成员变量是什么意思?你的意思是成员函数,不是吗? @bloody 我指的是我的 Player 类中的 protected: double _trust; 作为成员变量。

以上是关于使用类和函数来跟踪用户统计信息的主要内容,如果未能解决你的问题,请参考以下文章

类似触发器的系统来更新用户统计信息

如何理解 Oracle 中跟踪文件的统计信息。如CPU、经过时间、查询...等

如何从手动创建的 Firebase 动态链接中收集统计信息?

nginx/redis 和处理 url 中的跟踪参数

R语言使用skimr包的skim_with函数自定义指定需要查看的统计信息统计口径查看dataframe特定数据列的summary信息统计汇总信息(Specify statistics)

如何根据使用 dplyr 的组上的聚合函数计算新列(在汇总统计信息上添加汇总统计信息)?