友元函数无法访问私有成员
friend function cant access private memebers
我开始学习运算符重载,起初看起来很容易,但现在在尝试创建全局函数运算符时访问私有成员时遇到问题
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();
}
我没有看到那里有错误,但它一直显示在 visual studio 项上 class 成员是私有的(无法访问 em),如果我在 [=24] 之间切换=] 和 item.h header 订单,我可以访问项目私有成员,然后我失去对 player.hpp 私有成员的访问权限
如有任何帮助,我们将不胜感激。
首先,错误 #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) {
| ^~~~
修复很简单:
int main(int args, char* argv[])
或
int main([[maybe_unused]] int args, [[maybe_unused]] char* argv[])
甚至
int main()
错误#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);
| ^~~~~~
这更难解释。您的 class item
取决于 class player
而 player
取决于 item
。这是编译器不可能通过的。解决方案:
在item.h
中替换
#include "player.hpp"
和
class player;
这是一个前向声明。 Class item
仅在此处使用 player
:
friend player operator+(player &&obj,const item &tem);
也就是说,编译器只需要形成对player
的引用,它不需要详细了解player
到底是什么。这是一个常见的“技巧”:当class A只使用指向B的指针或引用时,B的前向声明就完全足够了。此外,消除#include
,您可以加快编译速度。
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;
| ^
不要使用你不理解的东西。或者更好:不要同时使用两个你不理解的东西。移动语义很少出现在移动构造函数之外。在您成为专家之前,请尽量避免在移动构造函数和移动 operator=
以外的地方使用 &&。实际上,即使您根本不使用它们,您的程序也将是完全正确的 - 不使用移动语义不会使程序不正确,它可能只会使它 运行 比使用移动语义慢一点被正确使用。所以,转:
friend player operator+(player &&obj,const item &tem);
进入
friend player operator+(player &obj, const item &tem);
此外,删除 player
和 any 中使用 &&
的移动构造函数,因为它什么也没动。你所做的就是向你的膝盖开枪。
错误#4
在所有这些更改之后,编译器提出了一系列类似类型的新投诉:
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
这是因为你搞砸了几乎所有的好友声明。
该修复类似于 `item.hpp" 中使用的修复,而不是
friend player operator+(player& obj,const player& tem);
声明
class item;
然后是真正的运算符+:
friend player operator+(player& obj, const item& tem);
错误 5
从 *obj.health += tem.health;
中删除 *
一般说明
- 不要在没有编译的情况下编写大量代码。如果你正在学习一门新语言/如何编程,写几行然后编译。通过这种方式,您将始终面临 1 个,也许是两个 bug,通常很容易定位。
- 不要一次学好几样东西。在这里,您表明您对以下方面的了解非常有限:
- 如何处理多个源文件/头文件,
- 什么是移动语义,
- 如何使用好友声明。
我什至没有检查你代码的质量,我只是试着让它编译。
- 如果您是 C++ 初学者,则不需要移动语义、友元声明、运算符重载。尝试使用这些功能,您会分散对真正重要目标的注意力。您不必成为 C++ 专家即可使用它。逐步学习并只使用您熟悉的工具,或者一次学习一件事。
我开始学习运算符重载,起初看起来很容易,但现在在尝试创建全局函数运算符时访问私有成员时遇到问题
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();
}
我没有看到那里有错误,但它一直显示在 visual studio 项上 class 成员是私有的(无法访问 em),如果我在 [=24] 之间切换=] 和 item.h header 订单,我可以访问项目私有成员,然后我失去对 player.hpp 私有成员的访问权限
如有任何帮助,我们将不胜感激。
首先,错误 #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) {
| ^~~~
修复很简单:
int main(int args, char* argv[])
或
int main([[maybe_unused]] int args, [[maybe_unused]] char* argv[])
甚至
int main()
错误#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);
| ^~~~~~
这更难解释。您的 class item
取决于 class player
而 player
取决于 item
。这是编译器不可能通过的。解决方案:
在item.h
中替换
#include "player.hpp"
和
class player;
这是一个前向声明。 Class item
仅在此处使用 player
:
friend player operator+(player &&obj,const item &tem);
也就是说,编译器只需要形成对player
的引用,它不需要详细了解player
到底是什么。这是一个常见的“技巧”:当class A只使用指向B的指针或引用时,B的前向声明就完全足够了。此外,消除#include
,您可以加快编译速度。
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;
| ^
不要使用你不理解的东西。或者更好:不要同时使用两个你不理解的东西。移动语义很少出现在移动构造函数之外。在您成为专家之前,请尽量避免在移动构造函数和移动 operator=
以外的地方使用 &&。实际上,即使您根本不使用它们,您的程序也将是完全正确的 - 不使用移动语义不会使程序不正确,它可能只会使它 运行 比使用移动语义慢一点被正确使用。所以,转:
friend player operator+(player &&obj,const item &tem);
进入
friend player operator+(player &obj, const item &tem);
此外,删除 player
和 any 中使用 &&
的移动构造函数,因为它什么也没动。你所做的就是向你的膝盖开枪。
错误#4
在所有这些更改之后,编译器提出了一系列类似类型的新投诉:
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
这是因为你搞砸了几乎所有的好友声明。 该修复类似于 `item.hpp" 中使用的修复,而不是
friend player operator+(player& obj,const player& tem);
声明
class item;
然后是真正的运算符+:
friend player operator+(player& obj, const item& tem);
错误 5
从 *obj.health += tem.health;
一般说明
- 不要在没有编译的情况下编写大量代码。如果你正在学习一门新语言/如何编程,写几行然后编译。通过这种方式,您将始终面临 1 个,也许是两个 bug,通常很容易定位。
- 不要一次学好几样东西。在这里,您表明您对以下方面的了解非常有限:
- 如何处理多个源文件/头文件,
- 什么是移动语义,
- 如何使用好友声明。
我什至没有检查你代码的质量,我只是试着让它编译。
- 如果您是 C++ 初学者,则不需要移动语义、友元声明、运算符重载。尝试使用这些功能,您会分散对真正重要目标的注意力。您不必成为 C++ 专家即可使用它。逐步学习并只使用您熟悉的工具,或者一次学习一件事。