C ++类和朋友

时间:2013-06-29 13:31:57

标签: c++ class friend

这是我的代码:

#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();成为它的朋友。但我仍然无法在功能中使用它的私有变量 我做错了什么,有更好的方法吗?

6 个答案:

答案 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之间没有关系,除了它可以访问私有成员 CC类型的对象。但是,看不到C类型的对象,即使有,也没有什么可以告诉编译器要从哪个对象str,或者甚至是在谈论strC中的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。但是静态成员将使该类的所有实例共享相同的值。