简体   繁体   中英

friend function cant access private memebers

i started learning about operators overloading, at first it seem to easy, but now am having a problem accessing private member when try to make a global funtion operator

player.hpp

#ifndef _PLAYER_HPP_
#define _PLAYER_HPP_

#include <iostream>
#include <string>
#include "item.h"

class player
{
    friend player operator+(player& obj, player& tem);
    static int numPlayer;
    float *health;
    int mspeed;
    int damage;
    int xp;
    std::string name;

public:
    // Constructors
    player(std::string = "player", float _health = 100, int _xp = 0);

    // Copy Constructor
    player(const player& obj);

    // Move Constructor
    player(player&& obj);

    // Functions
    void display();
    
    // Friends functions
    friend void test(player user);
    friend player operator+(player &&obj, const item &tem);
    // Diconstructors
    ~player();
};


#endif // _PLAYER_HPP_

player.cpp

#include "player.hpp"
#include "item.h"
#include <iostream>
#include <cstring>
#include <string>

int player::numPlayer = 0;

// Constructors
player::player(std::string _name, float _health, int _xp) {
    numPlayer++;
    this->health = new float;
    *this->health = _health;
    this->xp = _xp;
    this->name = _name;
    std::cout << "constructor for " << this->name << std::endl;
}

// Copy constructors
player::player(const player& obj) {
    this->health = new float;
    *this->health = *obj.health;
    this->xp = obj.xp;
    this->name = obj.name;
    std::cout << "copy constructor for " << this->name << std::endl;
}

// Move Constructors
player::player(player&& obj) {
    this->damage = 60;
    this->mspeed = 50;
    this->health = obj.health;
    this->xp = obj.xp;
    this->name = obj.name;
    obj.health = nullptr;
    std::cout << "Move constructor for " << this->name << std::endl;
}

void player::display() {
    std::cout << "========================" << std::endl
        << this->name << std::endl
        << *this->health << std::endl
        << this->xp << std::endl
        << this->damage << std::endl
        << this->mspeed << std::endl;
}

player::~player() {
    delete[] health;
    std::cout << "distruction for: " << name << std::endl;
}

void test(player user) {
    std::cout << user.name << std::endl;
}

player operator+(player&& obj, const item& tem) {
    *obj.health += tem.health;
    obj.damage += tem.damage;
    obj.mspeed += tem.ms;
    return obj;
}

item.h

#ifndef _ITEM_H_
#define _ITEM_H_
#include <iostream>
#include <string>
#include "player.hpp"

class item {
    int damage; // Bonus damage
    int health; // Bonus health
    int ms; // Bonus Movement speed
    std::string name; // item name

public:
    //constructor
    item(std::string name, int _damage = 0, int _health = 0, int _ms = 0)
        : name {name}, damage {_damage}, health{_health}, ms {_ms}{}
    
    friend player operator+(player &&obj,const item &tem);
};

#endif // _ITEM_

Main.cpp

#include <iostream>
#include <string>
#include "player.hpp"
#include "item.h"

player operator+(player&& obj, const item& tem);
void test(player user);

void main(int args, char* argv) {
    player a("YASOU96");
    item deathSword("death Sword", 150, 0, 20);
    a.display();
    a = a + deathSword;
    a.display();
}

i dont see that there is a mistake there but it keep showing on visual studio item class member are private (can't access em), nd if i switch between the player.hpp and item.h header order, i can have access to item private member, nd then i lose access on player.hpp private member

Any help would be appreciated.

First things first, Error #1:

main.cpp:9:1: error: ‘::main’ must return ‘int’
    9 | void main(int args, char* argv) {
      | ^~~~
main.cpp:9:6: warning: second argument of ‘int main(int, char*)’ should be ‘char **’ [-Wmain]
    9 | void main(int args, char* argv) {
      |      ^~~~

The fix is easy:

int main(int args, char* argv[])

or

int main([[maybe_unused]] int args, [[maybe_unused]] char* argv[])

or even

int main()

Error #2:

In file included from player.hpp:6,
                 from main.cpp:3:
item.h:18:12: error: ‘player’ does not name a type
   18 |     friend player operator+(player &&obj,const item &tem);
      |            ^~~~~~

This is more difficult to interpret. Your class item depends on class player and player depends on item . This is impossible for the compiler to go through. Solution:

In item.h replace

#include "player.hpp"

with

class player;

This is a forward declaration. Class item uses player only here:

    friend player operator+(player &&obj,const item &tem);

that is, the compiler needs to form only a reference to a player , it needs not to have the detailed knowledge about what player actually is. This is a common "trick": when class A uses only pointers or references to B, the forward declaration of B is completely enough. Moreover, be eliminating #include , you speed up the compilation a bit.

  main.cpp: In function ‘int main(int, char*)’:
main.cpp:13:9: error: cannot bind rvalue reference of type ‘player&&’ to lvalue of type ‘player’
   13 |     a = a + deathSword;
      |         ^

Don't use things you don't understand. Or better: don't use two things you don't understand at the same time. Move semantics is rarely seen outside move constructors. Until you're an expert, try and refrain from using && in places other than the move constructor and moving operator= . Actually, even if you won't use them at all, your program will be perfectly correct - not using move semantics does not make the program incorrect, it may only render it run a bit slower that it could with move semantics being used correctly. So, turn:

    friend player operator+(player &&obj,const item &tem);

into

    friend player operator+(player &obj, const item &tem);

Also, delete the move constructor in player and any cases where you use && , because it moves nothing. All you do is to shoot at your knee.

Error #4

After all these changes, the compiler presents a series of new complaints of similar type:

 player.cpp: In function ‘player operator+(player&&, const item&)’:
player.cpp:58:24: error: ‘int item::health’ is private within this context
   58 |     *obj.health += tem.health;
      |                        ^~~~~~
In file included from player.hpp:6,
                 from player.cpp:1:
item.h:11:9: note: declared private here
   11 |     int health; // Bonus health

This is because you messed up almost all friend declaration(s). The fix is similar to the one used in `item.hpp". Instead of

friend player operator+(player& obj,const  player& tem);

declare

class item;

and then the true operator+:

friend player operator+(player& obj, const item& tem);

Error 5 Remove * from *obj.health += tem.health;

GENERAL REMARKS

  • Don't write tons of code without compiling it. If you're learning a new language / how to program, write a few lines and compile. In this way you'll always face 1, perhaps two bugs, usually easy to localize.
  • Don't learn several things at a time. Here you've shown you have a very limited understanding of:
    • how to handle multiple source / header files,
    • what is move semantics,
    • how to use friend declarations.

and I didn't even look into the quality of your code, I just tried to made it compile.

  • If you're C++ beginner, you don't need move semantics, friend declaration, operator overloading. Trying to use these features, you're distracting your attention from really important objectives. You don't have to be a C++ expert to use it. Learn gradually and use only the tools you understand well, or learn one thing at a time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM