问题
让我们逐段查看您的代码:
#include <iostream>
#include <string>
using namespace std;
这里只是一个简短的说明:使用using namespace std; 是一个坏主意。
class C
{
private:
string str;
friend void func();
};
在这里你定义了一个类 C。你声明这个类的 objects 将包含一个字符串,它是私有的(即只能被类成员和朋友访问),你声明全局函数void func()一个朋友,也就是说,它被允许访问类C和任何C类型对象的私有成员(在本例中为str)。请注意,除了该权限之外,func 与 C 类没有任何关系。
void func()
{
str = "Lala";
cout << str << endl;
}
在这里,您尝试分配一个您从未声明过的变量str。请记住,func 与 C 类没有任何关系,只是它可以访问
C 和 C 类型的对象。但是,看不到C 类型的对象,即使有,也没有什么可以告诉编译器要从哪个对象str 中获取,甚至您在谈论str 中的@987654339 @。我会再次提醒您,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 成员的值为"Lala",而第二个对象的str 成员的值为"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 成员被分配了值"Lala"。在调用func 时,会创建该对象的副本,然后您可以从func 访问该对象。由于它是一个副本,它最初还包含相同的值 "Lala", whichfuncthen outputs. Then the assignment infuncchanges thestrmember *of that copy* to"Lele"and outputs that. The original object is not affected as the output inmain` 显示。
所以你看,可以有几个对象,重要的是你说你想访问哪个对象的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。
现在您再次直接访问作为参数从main 传递的对象,但这一次,您不保证不更改它,实际上您确实 更改了它。 main 的输出表明确实 main_object 已更改。
使变量成为静态成员
现在,您可能真的希望C 中只有一个str,而不是每个该类型的对象都有一个单独的str。如果您绝对肯定这是您想要的,那么您可以将 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!
现在您可以在没有 C 对象可用的情况下访问 str。但是请注意,您仍然需要告诉func 内部的编译器您要访问C 内部的str:
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 的语法在这方面具有误导性;实际上这里它的意思是“@987654399 @为object1的类型定义的,即C")。