【问题标题】:C++ class and friend [closed]C ++类和朋友[关闭]
【发布时间】:2013-06-29 13:31:57
【问题描述】:

这是我的代码:

#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();成为它的朋友。但我仍然不能在函数中使用它的私有变量。
我做错了什么,有没有更好的方法来做到这一点?

【问题讨论】:

  • func 应该在哪个对象上运行?
  • 怎么不行?

标签: c++ class friend


【解决方案1】:

它不起作用,因为void func(); 不是该类的成员函数,它只是被声明为它的友元函数,这意味着它可以访问私有成员。

您没有class C 的实例,因此您不可能引用任何有效的str 变量。

【讨论】:

    【解决方案2】:

    下次,请同时引用您遇到的错误。在这种情况下,将出现一个编译错误,指出符号“str”尚未在 func() 中定义。

    如果要访问C类实例的成员str,就需要这样一个实例,如:

    void func(){
        C c;
        c.str = "Lala";
        cout << c.str << endl;
    
    }
    

    【讨论】:

      【解决方案3】:

      func() 不是成员函数,它没有接收任何C 类型的参数,它应该对什么对象进行操作?

      func 必须是C 的成员函数(在这种情况下,您将在C 的实例上调用它,而friend 不是必需的),或者是接收某些参数的函数输入C(或创建一个本地C 对象),它可以在上面工作,甚至访问它的私有字段。

      【讨论】:

        【解决方案4】:

        这不起作用,因为 str 没有在 func() 中定义。 你应该有一个 C 的实例。

        void func()
        {
            C foo;
            foo.str = "Lala";
            cout << str << endl;
        }
        

        如果需要,可以将 C 实例作为参数传递:

        void func(C &foo)
        {
            foo.str = "Lala";
            cout << str << endl;
        }
        

        【讨论】:

        • @soon Meh 自从我用 C++ 编码以来已经太久了。
        【解决方案5】:

        问题

        让我们逐段查看您的代码:

        #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)。请注意,除了该权限之外,funcC 类没有任何关系。

        void func()
        {
                str = "Lala";
                cout << str << endl;
        
        }
        

        在这里,您尝试分配一个您从未声明过的变量str。请记住,funcC 类没有任何关系,只是它可以访问 CC 类型的对象。但是,看不到C 类型的对象,即使有,也没有什么可以告诉编译器要从哪个对象str 中获取,甚至您在谈论str 中的@987654339 @。我会再次提醒您,func 完全独立于 C,因此代码的解释方式与 C 不会将其声明为朋友的方式相同。

        int main()
        {
            func();
        }
        

        好的,这里没什么特别的,你只是打电话给func

        如何解决

        现在,如何修复您的代码?嗯,有几种可能:

        提供物品

        本地对象

        由于strC 类的对象 的成员,因此您需要该类的对象。例如,您可以这样做:

        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&amp; 表示“我想直接访问调用者给我的对象,但我保证不会更改它。” “直接访问”部分用&amp;表示,“我保证不改”用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,因为您再次处理不同的对象。

        当然,您可能确实想要更改传递给您的对象。然后你可以只使用&amp;而不使用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")。

        【讨论】:

          【解决方案6】:
          void func(C* object)
          {
                  object->str = "Lala";
                  cout << object->str << endl;
          
          }
          

          由于func 不是该类的成员,所以不能像object.func() 那样称呼它。因此,该函数将不知道您希望更改哪个类的对象。所以你必须明确地将对象指针传递给函数。使用参考也可以。

          或者您可以将str 声明为static。但是静态成员会使类的所有实例共享相同的值。

          【讨论】:

          • 由于 OP 是一个完整的初学者,我相信在这个答案中解释为什么您使用指针可能会很有用。另外为什么不使用参考?
          • 天啊,为什么我的投票被否决了?
          • 查看我的评论。顺便说一句,这不是我。
          猜你喜欢
          • 2013-03-14
          • 2010-09-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多