这是我的代码:
#include <iostream>
#include <string>
using namespace std;
class C
{
private:
string str;
friend void func();
};
void func()
{
str = "Lala";
cout << str << endl;
}
int main()
{
func();
}
我不明白为什么这不起作用。
在我更大的项目中,我想要使用类外的函数来访问类的私有变量
在这里,我创建了一个C类,并创建了一个函数func();成为它的朋友。但我仍然无法在功能中使用它的私有变量
我做错了什么,有更好的方法吗?
答案 0 :(得分:4)
它不起作用,因为void func();
不是类的成员函数,它只是声明为它的友元函数,这意味着它可以访问私有成员。
您没有class C
的实例,因此您无法引用任何有效的str
变量。
答案 1 :(得分:3)
下次还请引用您收到的错误。在这种情况下,会有一个编译错误,指出在func()中没有定义符号“str”。
如果要访问C类实例的成员str,则需要这样的实例,如:
void func(){
C c;
c.str = "Lala";
cout << c.str << endl;
}
答案 2 :(得分:3)
func()
不是一个成员函数,并且它没有接收到C
类型的任何参数,它应该在哪个对象上运行?
func
必须是C
的成员函数(在这种情况下,您将在C
的实例上调用它,并且friend
不是必需的),接收某个类型为C
的参数(或创建一个本地C
对象)的函数,它可以在其上工作,甚至可以访问其私有字段。
答案 3 :(得分:2)
这不起作用,因为str未在func()中定义。 你应该有一个C的实例。
void func()
{
C foo;
foo.str = "Lala";
cout << str << endl;
}
如果需要,可以将C实例作为参数传递:
void func(C &foo)
{
foo.str = "Lala";
cout << str << endl;
}
答案 4 :(得分:2)
让我们一块一块地看看你的代码:
#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
与课程C
无关。
void func()
{
str = "Lala";
cout << str << endl;
}
在这里,您尝试分配一个您从未声明过的变量str
。请记住,func
与类C
之间没有关系,除了它可以访问私有成员
C
和C
类型的对象。但是,看不到C
类型的对象,即使有,也没有什么可以告诉编译器要从哪个对象str
,或者甚至是在谈论str
在C
中的1}}。我会再次记住你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
成员被分配了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"
,编译器会抱怨(有办法告诉编译器)关闭它,但你不应该这样做;只要遵守你的承诺。但请注意,这仅适用于仅适用于该特定对象;例如,以下代码完全正常:< / p>
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
已更改。
现在,您真的可能希望str
中只有一个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
的类型定义的{{1}},即{{1}}”。
答案 5 :(得分:1)
void func(C* object)
{
object->str = "Lala";
cout << object->str << endl;
}
由于func
不是该类的成员,因此您无法像object.func()
那样调用它。因此,该函数将不知道您希望更改的类的哪个对象。所以你必须显式地将对象指针传递给函数。使用引用也可以。
或者您可以将str
声明为static
。但是静态成员将使该类的所有实例共享相同的值。