【问题标题】:Class private member - array accessing failed类私有成员 - 数组访问失败
【发布时间】:2016-02-20 17:13:30
【问题描述】:

所以我用 C++ 编写了这段代码,这只是学习 C++ 的练习:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


int random(int max){
    srand(time(NULL));
    return rand() % max;
}


class player{
    public:
        player(){
            liv = 5;
            mun = 3;
        }
        void Rename(char name[]){
            name = name;
        }
        void set_group(player pl[]){
            pl = pl;
        }
        void fire(){
            if (liv > 0 and mun){
                mun -= 1;
                int hit = random(10);
                printf("%d: ", hit);
                printf("%s", pl[hit].get_name());
                if (hit < 5 and pl[hit].live()){
                    pl[hit].hit();
                    printf("Player %s hit player %s!", name, pl[hit].get_name());
                }
            }
        }
        bool live(){
            return liv;
        }
        void hit(){
            liv -= 1;
        }
        char * get_name(){
            return name;
        }
    private:
        int liv, mun;
        char name[100];
        player *pl;
};


main(){
    player pl[5];
    char str[100];
    int x;
    for (x=0;x<5;x++){
        sprintf(str, "%d", x + 1);
        pl[x].Rename(str);
        pl[x].set_group(pl);
    }
    pl[0].fire();
}

编译器 (TDM-GCC 4.9.2 32-bit) 编译代码并返回 0 个警告和 0 个错误。
当我运行程序时,我收到消息:classes.exe has encountered a problem and needs to close. We are sorry for the inconvenience.

我调试了一下,发现printf("%s", pl[hit].get_name());这行有问题(其实是调试行,后面的行确实有问题,但都是一回事)。我也认为访问 pl 是个问题。

我对 C 和 C++(尤其是 C+)比较陌生,我的主要编程语言是 Python,所以不要对我的错误笑太多。

【问题讨论】:

  • 错误1:你不应该在你的随机函数中调用srand(time(NULL));,因为如果你在一秒钟内多次调用它,你总是会得到相同的随机数。相反,您应该只设置一次种子。
  • pl = pl; 并没有按照你的想法去做
  • pl = pl; 变量名称在 c++ 中是免费提供的,不要为成员变量和参数回收 pl 名称;在这条指令中,哪个pl 分配给了哪个pl?我不知道,也不想知道:只是使用不同的名称!

标签: c++ class oop private member


【解决方案1】:

这实际上什么都不做。

void Rename(char name[]){
    name = name;
}

其实是等价的

void Rename(char *p){
    p = p;
}

你想要

void Rename(char name[]){
    strcpy(this->name, name);
}

但更好的是使用不冲突的名称并添加一些错误检查。

[ EDIT ] "set_group(player pl[])" 也存在同样的问题 - 感谢@Kevin 发现。

【讨论】:

  • “这实际上什么也没做”...你是什么意思?
  • @tobi303 “name”参数隐藏了“name”类成员。在这种情况下,最终结果是无操作,请参见第二段。
  • 感谢您的帮助,但我仍然收到错误消息(对您有用吗?)。
  • 你在set_group有同样的问题
【解决方案2】:

我建议你改变几件事:

  • 不应在每次滚动新随机数时设置种子。尝试在循环中多次调用随机函数,您会发现每次都得到相同的数字。
  • 使用 std::vector 代替 c 样式数组
  • 使用std::string 代替字符
  • 如果您使用std::cout 而不是printf,则不必自己处理格式。
  • 您的player 构造函数未设置名称。因此,可以创建一个处于不完整状态(即没有名字)的玩家
  • 在构造函数中使用初始化列表更有效
  • 玩家真的必须知道自己属于哪个组吗?我建议更改它,因为 atm 您将单个玩家与他们之间的交互方式混合在一起。
  • 如果玩家组只有一个玩家怎么办?您的代码无法处理这种情况。
  • 玩家可以使用您的代码击中自己。不确定这是否是您想要的;)

总的来说,它可能看起来像这样:

#include <time.h>
#include <string>
#include <iostream>
#include <vector>
#include <cstdlib> // for rand()

void init_random(){srand(time(0));}
int random(int max){return rand() % max;}

class player{
public:
    player(std::string name) : liv(5),mun(3),name(name){}
    void Rename(std::string newname){name = newname;}
    bool live(){return liv;}
    void hit(){liv -= 1;}
    void fire(){mun -= 1;}
    std::string get_name(){return name;}
private:
    int liv, mun;
    std::string name;
};

class player_group{
public:
    void addPlayer(const player& p){players.push_back(p);}
    void fire(int i){
        // avoid wrong input
        if (i>=0 && i<players.size() && players.size()>1){
            players[i].fire();
            int other = i;
            // avoid player hitting himself
            while (other == i){other = random(players.size());}
            players[other].hit();
            std::cout << "Player " 
                      << players[i].get_name() 
                      << " hits player " 
                      << players[other].get_name() 
                      << std::endl;
        }
    }
private:
    std::vector<player> players;
};

int main() {
    init_random();
    player_group pg;
    pg.addPlayer(player("Peter"));
    pg.addPlayer(player("Paul"));
    pg.fire(0);
}

自 C++11 以来,有更好的随机生成器。如果您需要高质量的随机性,您应该使用它们而不是 rand(),后者具有 some issues。但是,在这种情况下,恕我直言 rand() 就可以了。

还要注意,在我的代码中,玩家组“拥有”玩家。我的意思是 addPlayer() 调用 push_back() 向向量添加一个副本。如果这不是您想要的,您可以考虑将player_group 更改为保留std::vector&lt;player*&gt; 以避免复制。

【讨论】:

  • 这个void Rename(std::string name){name = name;} 也是空操作。请注意,您可以使用这样的东西的唯一地方是初始化其子对象的构造函数,例如player(std::string name) : name(name) 确实如您所愿。
  • @dxiv hm 我想你是对的。我摆脱了到处写this-&gt; 的java 习惯,但不知何故我一定错过了这一点。
  • 我想你忘了包含 stdlib.h,我包含了它,但我仍然收到 3 个错误:第 45 行:[Error] 'vector' in namespace 'std' does not name a template type,第 28 行:[Error] 'players' was not declared in this scope,第 31 行:[Error] 'players' was not declared in this scope
  • @knowledge 是的,有些包含在复制和粘贴时丢失了,我会修复它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-09
  • 1970-01-01
  • 1970-01-01
  • 2011-07-27
  • 2023-03-22
  • 2020-01-19
  • 2013-05-23
相关资源
最近更新 更多