问题
让我们一块一块地看你的代码:
#include <iostream>
#include <string>
using namespace std;
这里只是一个简短的说明:使用using namespace std;
.
class C
{
private:
string str;
friend void func();
};
这里定义了一个类C,你声明这个类的对象会包含一个字符串,这个字符串是私有的(即只能被类成员和好友访问),你声明全局函数void func()
为好友,即允许访问str
类C
和任何类型对象的私有成员(在这种情况下) C
。请注意,除了该权限之外,func
与 class 没有任何关系C
。
void func()
{
str = "Lala";
cout << str << endl;
}
在这里,您尝试分配一个str
您从未声明过的变量。请记住,除了可以访问 type 的私有成员
和对象之外,func
与该类没有任何关系。但是,看不到类型的对象,即使有,也没有什么可以告诉编译器要从哪个对象中获取,甚至您正在谈论in 。我会再次记住您,它完全独立于,因此代码的解释方式与不会将其声明为朋友的方式相同。C
C
C
C
str
str
C
func
C
C
int main()
{
func();
}
好的,这里没什么特别的,你只是在打电话func
。
如何修复它
现在,如何修复您的代码?嗯,有几种可能:
供应对象
本地对象
由于是类对象str
的成员,因此您需要该类的对象。所以你可以例如做:C
void func()
{
C object;
object.str = "Lala";
std::cout << object.str << std::endl;
}
在这里,您在 中创建一个本地对象,为该对象的func
成员分配一个值,然后将其输出。要查看不同的对象具有不同的成员,您可以例如编写: str
void func()
{
C object1, object2;
object1.str = "Lala";
object2.str = "Lele";
std::cout << object1.str << " -- " << object2.str << "\n";
}
这Lala -- Lele
是因为第一个对象的str
成员具有 value"Lala"
而第二个对象的str
成员具有 value "Lele"
。
函数参数
另一种选择是您将对象作为参数传递,例如
void func(C object)
{
std::cout << object.str << " -- ";
object.str = "Lele";
std::cout << object.str << " -- ";
}
int main()
{
C main_object;
main_object.str = "Lala";
func(main_object);
std::cout << object.str << std::endl;
}
这打印Lala -- Lele -- Lala
。
这里发生的情况main
是创建了一个对象,其str
成员被分配了 valeu "Lala"
。在调用 时func
,会创建该对象的副本,然后您可以从 访问该副本func
。由于它是一个副本,它最初还包含与"Lala", which
func then outputs. Then the assignment in
func changes the
str member *of that copy* to
"Lele" and outputs that. The original object is not affected as the output in
main` 显示的相同的值。
所以你看,可以有几个对象,你说你想访问哪个str
对象的成员是至关重要的。
现在,如果您不打算更改被调用函数中的对象,则制作副本只是浪费时间,因此您也可以将其作为对 const 的引用传递:
void func(C const& object)
{
std::cout << object.str << std::endl;
}
int main()
{
C main_object;
main_object.str = "Lala";
func(main_object);
}
参数C const&
说“我想直接访问调用者给我的对象,但我保证不会改变它。” “直接访问”部分用 表示&
,“我保证不改变它”用 表示const
。编译器实际上会检查您是否遵守诺言并且不要尝试更改它(也就是说,如果func
您尝试这样做object.str = "Lele"
,编译器会抱怨(有一些方法可以告诉编译器闭嘴,但您不应该)不要那样做;只要信守诺言)。但是请注意,这再次仅适用于该特定对象;例如,以下代码完全可以:
void func(C const& object)
{
C another_object;
another_object.str = "Lele";
std::cout << object.str << " -- " << another_object.str << std::endl;
}
int main()
{
C main_object;
main_object.str = "Lala";
func(main_object);
}
这不会产生错误并打印Lala -- Lele
,因为您再次处理不同的对象。
当然,您可能确实想更改传递给您的对象。然后你可以&
不使用const
:
void func(C& object)
{
std::cout << object.str << " -- ";
object.str = "Lele";
std::cout << object.str << " -- ";
}
int main()
{
C main_object;
main_object.str = "Lala";
func(main_object);
std::cout << object.str << std::endl;
}
这打印Lala -- Lele -- Lele
。
现在您再次直接访问作为参数传递的对象 from main
,但这一次,您不保证不更改它,实际上您确实更改了它。的输出main
表明确实main_object
发生了变化。
使变量成为静态成员
现在,您可能真的希望只有一个str
in C
,而不是每个该类型的对象都有一个单独的。如果您绝对肯定这是您想要的,那么您可以创建str
该类的静态成员:
class C
{
private:
static std::string str; // note the keyword "static" here
friend void func();
};
std::string C::str; // You have to have an extra definition for class static variables!
现在您可以str
在没有C
可用对象的情况下访问。但是请注意,您仍然需要告诉内部的编译器func
您要访问str
内部C
:
void func()
{
C::str = "Lala";
std::cout << C::str << std::endl;
}
您还可以访问对象上的变量,就好像它是该对象的成员一样。但是请注意,这并不意味着不同的对象仍然有自己的str
. 例如,随着类定义的改变,我们将得到与上面代码不同的行为:
void func()
{
C object1, object2;
object1.str = "Lala";
object2.str = "Lele";
std::cout << object1.str << " -- " << object2.str << "\n";
}
现在我们将得到输出Lele -- Lele
,因为只有一个str
不依赖于对象(object1.str
在这种情况下的语法在这方面具有误导性;实际上这里它的意思是“为 的类型str
定义的,即”)。object1
C