【问题标题】:Separate declaration for friend function友元函数的单独声明
【发布时间】:2015-02-25 04:01:46
【问题描述】:

我正在阅读 C++ Primer 书。它说:

朋友声明仅指定访问权限。这不是一般性声明 功能。如果我们希望类的用户能够调用朋友函数,那么我们 还必须将函数声明与友元声明分开。 为了让类的用户可以看到一个朋友,我们通常声明每个朋友 (在类之外)与类本身在同一个标​​题中。

注意代码中的箭头。这在参考上述文本的那些特定点上提出了我的问题。

header.h

#ifndef HEADER_H
#define HEADER_H

#include <iostream>
#include <string>

using namespace std;

class Husband{
    friend void change_salary(int changed_salary, Husband &ob);

public:
    Husband() {}
    Husband(unsigned new_salary) : salary{ new_salary } {}

private:
    int salary;

};

//void change_salary(int changed_salary, Husband &ob);  <----Code Compiles without even this declaration

#endif

main.cpp

#include "header.h"

void change_salary(int changed_salary, Husband &ob)
{
    cout << "salary increased by 1000";
    ob.salary = changed_salary;
}


int main()
{
    Husband hs1{ 3000 };

    change_salary(4000, hs1);  // <---- Able to use function without explicit declaration outside of class in header

    return 0; 
}

【问题讨论】:

  • 尝试将change_salary 的定义移动到husband.cpp。然后你需要在husband.h 中声明函数。
  • @AustinMullins 现在我将 change_salary 代码保存在丈夫.cpp 中并包含“header.h” .....即使这样我的 main.cpp 也可以正确编译,甚至无需单独声明

标签: c++


【解决方案1】:

如果你在声明它的同一个文件中使用函数,你不需要在头文件中使用原型,在它被声明之后,这就是你在 main.cpp 中所做的。

将原型放在头文件中有助于其他文件中的代码,或者在同一个文件但更高的文件中,找到函数。在头文件中创建原型以使 API 对人类读者清晰可见,这通常是一种很好的做法。但在你这里的情况下,并不严格要求编译。

【讨论】:

  • 所以这意味着我可能有也可能没有(我的选择)?但如果我采用适当的系统方式,那么我必须拥有它?
  • C 编译器会在抛出错误之前尝试一些事情来找到你的函数,因此它实际上可能会在编译时出现关于“隐式声明”的警告。
  • 你是对的,如果在没有事先可见声明/定义的情况下使用函数,C 编译器会警告隐式声明,但 C++ 编译器会在此时抛出错误。 (cc @androidplusios.design)
【解决方案2】:

友元函数声明是您的类设计的一部分。如果没有在类头(或某些包含的头)中声明函数,您的设计是不完整的(强制用户实现该函数或为某些用户实现打开大门或导致单定义规则 (ODR) 违规)。

【讨论】:

    【解决方案3】:

    您在使用它的main() 的定义之前提供了change_salary 的定义,因此该函数始终可见且没有问题。但假设您将定义移至 main() 的下方(或移至单独的 .cpp 文件)。

    int main()
    {
        Husband hs1{ 3000 };
        change_salary(4000, hs1);
    }
    
    void change_salary(int changed_salary, Husband &ob)
    {
        cout << "salary increased by 1000";
        ob.salary = changed_salary;
    }
    

    即使在这种情况下,代码也将继续编译,因为change_salary 将被argument dependent name lookup 找到(因为第二个参数的类型为Husband&amp;)。

    现在让我们尝试通过在main() 中形成指向change_salary 的指针来显式引用它。

    void (*p)(int, Husband&) = &change_salary;
    

    这将fail to compile,因为ADL 在这种情况下不适用,change_salary 的定义对main() 不可见。

    但是,如果您在标题中取消注释 change_salary 的声明,则 code will compile。这大概就是这本书所说的让班级的用户看到朋友时的意思。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多