精华内容
下载资源
问答
  • C++——友元函数&内联函数

    千次阅读 多人点赞 2018-12-07 23:55:15
    友元函数 类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。 友元可以是一个函数,该函数被...

    友元函数

    类的友元函数是定义在类外部但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数

    友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。

    如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend,如下所示:

    class Box
    {
       double width;
    public:
       double length;
       friend void printWidth( Box box );
       void setWidth( double wid );
    };
    #include <iostream>
     
    using namespace std;
     
    class Box
    {
       double width;
    public:
       friend void printWidth( Box box );
       void setWidth( double wid );
    };
    
    // 成员函数定义
    void Box::setWidth( double wid )
    {
        width = wid;
    }
    
    // printWidth() 不是任何类的成员函数
    void printWidth( Box box )
    {
       /* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
       cout << "Width of box : " << box.width <<endl;
    }
     
    // 程序的主函数
    int main( )
    {
       Box box;
     
       // 使用成员函数设置宽度
       box.setWidth(10.0);
       
       // 使用友元函数输出宽度
       printWidth( box );
     
       return 0;
    }
    /*输出结果是
    Width of box : 10
    */

    内联函数

    内联函数是通常与类一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。

    对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。

    如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义。如果已定义的函数多于一行,编译器会忽略 inline 限定符。

    在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符。

     

    #include <iostream>
     
    using namespace std;
    
    inline int Max(int x, int y)
    {
       return (x > y)? x : y;
    }
    
    // 程序的主函数
    int main( )
    {
    
       cout << "Max (20,10): " << Max(20,10) << endl;
       cout << "Max (0,200): " << Max(0,200) << endl;
       cout << "Max (100,1010): " << Max(100,1010) << endl;
       return 0;
    }

    以下内容转载自:https://blog.csdn.net/u011327981/article/details/50601800/

    1.  内联函数

    在C++中我们通常定义以下函数来求两个整数的最大值:

    复制代码 代码如下:


    int max(int a, int b)
    {
     return a > b ? a : b;
    }

    为这么一个小的操作定义一个函数的好处有:

    ① 阅读和理解函数 max 的调用,要比读一条等价的条件表达式并解释它的含义要容易得多

    ② 如果需要做任何修改,修改函数要比找出并修改每一处等价表达式容易得多

    ③ 使用函数可以确保统一的行为,每个测试都保证以相同的方式实现

    ④ 函数可以重用,不必为其他应用程序重写代码

    虽然有这么多好处,但是写成函数有一个潜在的缺点:调用函数比求解等价表达式要慢得多。在大多数的机器上,调用函数都要做很多工作:调用前要先保存寄存器,并在返回时恢复,复制实参,程序还必须转向一个新位置执行

    C++中支持内联函数,其目的是为了提高函数的执行效率,用关键字 inline 放在函数定义(注意是定义而非声明,下文继续讲到)的前面即可将函数指定为内联函数,内联函数通常就是将它在程序中的每个调用点上“内联地”展开,假设我们将 max 定义为内联函数:

    复制代码 代码如下:


    inline int max(int a, int b)
    {
     return a > b ? a : b;
    }

    则调用: cout<<max(a, b)<<endl;


    在编译时展开为: cout<<(a > b ? a : b)<<endl;

    从而消除了把 max写成函数的额外执行开销

    2.  内联函数和宏

    无论是《Effective C++》中的 “Prefer consts,enums,and inlines to #defines” 条款,还是《高质量程序设计指南——C++/C语言》中的“用函数内联取代宏”,宏在C++中基本是被废了,在书《高质量程序设计指南——C++/C语言》中这样解释到:

    3.  将内联函数放入头文件

    关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。

    如下风格的函数 Foo 不能成为内联函数:

    复制代码 代码如下:


    inline void Foo(int x, int y);   // inline 仅与函数声明放在一起   
    void Foo(int x, int y)
    {
     ...

    而如下风格的函数 Foo 则成为内联函数:

    复制代码 代码如下:


    void Foo(int x, int y);   
    inline void Foo(int x, int y)   // inline 与函数定义体放在一起
    {
     ...

    所以说,C++ inline函数是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了 inline 关键字,但我认为 inline 不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。

    定义在类声明之中的成员函数将自动地成为内联函数,例如:

    复制代码 代码如下:


    class A
    {  
    public:
     void Foo(int x, int y) { ... }   // 自动地成为内联函数  

    但是编译器是否将它真正内联则要看 Foo函数如何定义

    内联函数应该在头文件中定义,这一点不同于其他函数。编译器在调用点内联展开函数的代码时,必须能够找到 inline 函数的定义才能将调用函数替换为函数代码,而对于在头文件中仅有函数声明是不够的。

    当然内联函数定义也可以放在源文件中,但此时只有定义的那个源文件可以用它,而且必须为每个源文件拷贝一份定义(即每个源文件里的定义必须是完全相同的),当然即使是放在头文件中,也是对每个定义做一份拷贝,只不过是编译器替你完成这种拷贝罢了。但相比于放在源文件中,放在头文件中既能够确保调用函数是定义是相同的,又能够保证在调用点能够找到函数定义从而完成内联(替换)。

    但是你会很奇怪,重复定义那么多次,不会产生链接错误?

    我们来看一个例子:

    A.h :

    复制代码 代码如下:


    class A
    {
    public:
     A(int a, int b) : a(a),b(b){}
     int max();

    private:
     int a;
     int b;
    };

    A.cpp : 

    复制代码 代码如下:


    #include "A.h"

    inline int A::max()
    {
     return a > b ? a : b;
    }

    Main.cpp : 

    复制代码 代码如下:


    #include <iostream>
    #include "A.h"
    using namespace std;

    inline int A::max()
    {
     return a > b ? a : b;
    }

    int main()
    {
     A a(3, 5);
     cout<<a.max()<<endl;
     return 0;
    }

    一切正常编译,输出结果:5

     


    倘若你在Main.cpp中没有定义max内联函数,那么会出现链接错误:

    error LNK2001: unresolved external symbol "public: int __thiscall A::max(void)" (?max@A@@QAEHXZ)main.obj
    找不到函数的定义,所以内联函数可以在程序中定义不止一次,只要 inline 函数的定义在某个源文件中只出现一次,而且在所有源文件中,其定义必须是完全相同的就可以。

    在头文件中加入或修改 inline 函数时,使用了该头文件的所有源文件都必须重新编译。

    4.  慎用内联

    内联虽有它的好处,但是也要慎用,以下摘自《高质量程序设计指南——C++/C语言》:

    而在Google C++编码规范中则规定得更加明确和详细:

    内联函数:

    Tip: 只有当函数只有 10 行甚至更少时才将其定义为内联函数.

    定义: 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用.
    优点: 当函数体比较小的时候, 内联该函数可以令目标代码更加高效. 对于存取函数以及其它函数体比较短, 性能关键的函数, 鼓励使用内联.
    缺点: 滥用内联将导致程序变慢. 内联可能使目标代码量或增或减, 这取决于内联函数的大小. 内联非常短小的存取函数通常会减少代码大小, 但内联一个相当大的函数将戏剧性的增加代码大小. 现代处理器由于更好的利用了指令缓存, 小巧的代码往往执行更快。
    结论: 一个较为合理的经验准则是, 不要内联超过 10 行的函数. 谨慎对待析构函数, 析构函数往往比其表面看起来要更长, 因为有隐含的成员和基类析构函数被调用!
    另一个实用的经验准则: 内联那些包含循环或 switch 语句的函数常常是得不偿失 (除非在大多数情况下, 这些循环或 switch 语句从不被执行).
    有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数和递归函数就不会被正常内联. 通常, 递归函数不应该声明成内联函数.(递归调用堆栈的展开并不像循环那么简单, 比如递归层数在编译时可能是未知的, 大多数编译器都不支持内联递归函数). 虚函数内联的主要原因则是想把它的函数体放在类定义内, 为了图个方便, 抑或是当作文档描述其行为, 比如精短的存取函数.

    -inl.h文件:


    Tip: 复杂的内联函数的定义, 应放在后缀名为 -inl.h 的头文件中.


    内联函数的定义必须放在头文件中, 编译器才能在调用点内联展开定义. 然而, 实现代码理论上应该放在 .cc 文件中, 我们不希望 .h 文件中有太多实现代码, 除非在可读性和性能上有明显优势.

    如果内联函数的定义比较短小, 逻辑比较简单, 实现代码放在 .h 文件里没有任何问题. 比如, 存取函数的实现理所当然都应该放在类定义内. 出于编写者和调用者的方便, 较复杂的内联函数也可以放到 .h 文件中, 如果你觉得这样会使头文件显得笨重, 也可以把它萃取到单独的 -inl.h 中. 这样把实现和类定义分离开来, 当需要时包含对应的 -inl.h 即可。

     

    部分资料来源于菜鸟教程

    展开全文
  • 类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。 友元可以是一个函数,该函数被称为友元函数...

    类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数
    友元可以是一个函数,该函数被称为友元函数;友元也可以是一个,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
    如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend,如下所示:

    class Box
    {
       double width;
    public:
       double length;
       friend void printWidth( Box box );
       void setWidth( double wid );
    };
    

    声明类 ClassTwo 的所有成员函数作为类 ClassOne的友元,需要在类 ClassOne的定义中放置如下声明:

    friend class ClassTwo;
    

    请看下面的程序:
    实例

    #include <iostream>
    
    using namespace std;
    
    class Box
    {
        double width;
    public:
        friend void printWidth(Box box);
        friend class BigBox;
        void setWidth(double wid);
    };
    
    class BigBox
    {
    public :
        void Print(int width, Box &box)
        {
            // BigBox是Box的友元类,它可以直接访问Box类的任何成员
            box.setWidth(width);
            cout << "Width of box : " << box.width << endl;
        }
    };
    
    // 成员函数定义
    void Box::setWidth(double wid)
    {
        width = wid;
    }
    
    // 请注意:printWidth() 不是任何类的成员函数
    void printWidth(Box box)
    {
        /* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
        cout << "Width of box : " << box.width << endl;
    }
    
    // 程序的主函数
    int main()
    {
        Box box;
        BigBox big;
    
        // 使用成员函数设置宽度
        box.setWidth(10.0);
    
        // 使用友元函数输出宽度
        printWidth(box);
    
        // 使用友元类中的方法设置宽度
        big.Print(20, box);
    
        getchar();
        return 0;
    }
    

    当上面的代码被编译和执行时,它会产生下列结果:

    Width of box : 10
    
    友元函数的使用

    因为友元函数没有this指针,则参数要有三种情况:

    • 要访问非static成员时,需要对象做参数;
    • 要访问static成员或全局变量时,则不需要对象做参数;
    • 如果做参数的对象是全局对象,则不需要对象做参数.
    • 可以直接调用友元函数,不需要通过对象或指针

    实例代码:

    class INTEGER
    {
        friend void Print(const INTEGER& obj);//声明友元函数
    };
    
    void Print(const INTEGER& obj)
    {
        //函数体
    }
    
    void main()
    {
        INTEGER obj;
        Print(obj);//直接调用
    }
    

    C++ 内联函数

    C++ 内联函数是通常与一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。
    对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。
    如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline在调用函数之前需要对函数进行定义。如果已定义的函数多于一行,编译器会忽略 inline 限定符。
    在类定义中的定义的函数都是内联函数,即使没有使用inline说明符。
    下面是一个实例,使用内联函数来返回两个数中的最大值:

    #include <iostream>
     
    using namespace std;
    
    inline int Max(int x, int y)
    {
       return (x > y)? x : y;
    }
    
    // 程序的主函数
    int main( )
    {
    
       cout << "Max (20,10): " << Max(20,10) << endl;
       cout << "Max (0,200): " << Max(0,200) << endl;
       cout << "Max (100,1010): " << Max(100,1010) << endl;
       return 0;
    }
    

    当上面的代码被编译和执行时,它会产生下列结果:

    Max (20,10): 20
    Max (0,200): 200
    Max (100,1010): 1010
    

    内联函数inline:引入内联函数的目的是为了解决程序中函数调用的效率问题,这么说吧,程序在编译器编译的时候,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体进行替换,而对于其他的函数,都是在运行时候才被替代。这其实就是个空间代价换时间的i节省。所以内联函数一般都是1-5行的小函数。在使用内联函数时要留神:

    1. 在内联函数内不允许使用循环语句和开关语句;
    2. 内联函数的定义必须出现在内联函数第一次调用之前;
    3. 类结构中所在的类说明内部定义的函数是内联函数。

    内联函数
    Tip: 只有当函数只有 10 行甚至更少时才将其定义为内联函数.
    定义: 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用.
    优点: 当函数体比较小的时候, 内联该函数可以令目标代码更加高效. 对于存取函数以及其它函数体比较短, 性能关键的函数, 鼓励使用内联.
    缺点: 滥用内联将导致程序变慢. 内联可能使目标代码量或增或减, 这取决于内联函数的大小. 内联非常短小的存取函数通常会减少代码大小, 但内联一个相当大的函数将戏剧性的增加代码大小. 现代处理器由于更好的利用了指令缓存, 小巧的代码往往执行更快。
    结论: 一个较为合理的经验准则是, 不要内联超过 10 行的函数. 谨慎对待析构函数, 析构函数往往比其表面看起来要更长, 因为有隐含的成员和基类析构函数被调用!
    另一个实用的经验准则: 内联那些包含循环switch 语句的函数常常是得不偿失 (除非在大多数情况下, 这些循环或 switch 语句从不被执行).

    有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数递归函数就不会被正常内联.
    通常, 递归函数不应该声明成内联函数.(递归调用堆栈的展开并不像循环那么简单, 比如递归层数在编译时可能是未知的, 大多数编译器都不支持内联递归函数).
    虚函数内联的主要原因则是想把它的函数体放在类定义内, 为了图个方便, 抑或是当作文档描述其行为, 比如精短的存取函数.

    this 指针

    C++中,每一个对象都能通过this指针来访问自己的地址。this指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象
    友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。
    下面的实例有助于更好地理解 this 指针的概念:
    实例

    #include <iostream>
     
    using namespace std;
     
    class Box
    {
       public:
          // 构造函数定义
          Box(double l=2.0, double b=2.0, double h=2.0)
          {
             cout <<"Constructor called." << endl;
             length = l;
             breadth = b;
             height = h;
          }
          double Volume()
          {
             return length * breadth * height;
          }
          int compare(Box box)
          {
             return this->Volume() > box.Volume();
          }
       private:
          double length;     // Length of a box
          double breadth;    // Breadth of a box
          double height;     // Height of a box
    };
     
    int main(void)
    {
       Box Box1(3.3, 1.2, 1.5);    // Declare box1
       Box Box2(8.5, 6.0, 2.0);    // Declare box2
     
       if(Box1.compare(Box2))
       {
          cout << "Box2 is smaller than Box1" <<endl;
       }
       else
       {
          cout << "Box2 is equal to or larger than Box1" <<endl;
       }
       return 0;
    }
    

    当上面的代码被编译和执行时,它会产生下列结果:

    Constructor called.
    Constructor called.
    Box2 is equal to or larger than Box1
    

    引入 this:

    当我们调用成员函数时,实际上是替某个对象调用它

    成员函数通过一个名为 this额外隐式参数来访问调用它的那个对象,当我们调用一个成员函数时,用请求该函数的对象地址初始化this。例如,如果调用 total.isbn()则编译器负责把total的地址传递给 isbn 的隐式形参this,可以等价地认为编译器将该调用重写成了以下形式:

    //伪代码,用于说明调用成员函数的实际执行过程
    Sales_data::isbn(&total)
    

    其中,调用Sales_dataisbn成员时传入了 total的地址。
    在成员函数内部,我们可以直接使用调用该函数的对象的成员,而无须通过成员访问运算符来做到这一点,因为this所指的正是这个对象。任何对类成员的直接访问都被看作是对 this 的隐式引用,也就是说,当isbn使用 bookNo时,它隐式地使用this指向的成员,就像我们书写了this->bookNo 一样。

    对于我们来说,this形参是隐式定义的。实际上,任何自定义名为 this的参数或变量的行为都是非法的。我们可以在成员函数体内部使用 this,因此尽管没有必要,我们还是能把isbn定义成如下形式:

    std::string isbn() const { return this->bookNo; }
    

    因为this的目的总是指向“这个”对象,所以 this 是一个常量指针,我们不允许改变this中保存的地址。

    #include <iostream>
    using namespace std;
    
    class Box{
        public:
            Box(){;}
            ~Box(){;}
            Box* get_address()   //得到this的地址
            {
                return this;
            }
    };
    
    int main(){
        
        Box box1;
        Box box2;
        // Box* 定义指针p接受对象box的get_address()成员函数的返回值,并打印
        
        Box* p = box1.get_address();  
        cout << p << endl;
        
        p = box2.get_address();
        cout << p << endl; 
    
        return 0;
    }
    

    this 指针的类型可理解为 Box*

    此时得到两个地址分别为box1box2对象的地址。

    C++ 指向类的指针

    一个指向 C++ 类的指针与指向结构的针类似,访问指向类的指针的成员,需要使用成员访问运算符->,就像访问指向结构的指针一样。与所有的指针一样,您必须在使用指针之前,对指针进行初始化。
    下面的实例有助于更好地理解指向类的指针的概念:

    #include <iostream>
     
    using namespace std;
    
    class Box
    {
       public:
          // 构造函数定义
          Box(double l=2.0, double b=2.0, double h=2.0)
          {
             cout <<"Constructor called." << endl;
             length = l;
             breadth = b;
             height = h;
          }
          double Volume()
          {
             return length * breadth * height;
          }
       private:
          double length;     // Length of a box
          double breadth;    // Breadth of a box
          double height;     // Height of a box
    };
    
    int main(void)
    {
       Box Box1(3.3, 1.2, 1.5);    // Declare box1
       Box Box2(8.5, 6.0, 2.0);    // Declare box2
       Box *ptrBox;                // Declare pointer to a class.
    
       // 保存第一个对象的地址
       ptrBox = &Box1;
    
       // 现在尝试使用成员访问运算符来访问成员
       cout << "Volume of Box1: " << ptrBox->Volume() << endl;
    
       // 保存第二个对象的地址
       ptrBox = &Box2;
    
       // 现在尝试使用成员访问运算符来访问成员
       cout << "Volume of Box2: " << ptrBox->Volume() << endl;
      
       return 0;
    }	
    

    当上面的代码被编译和执行时,它会产生下列结果:

    Constructor called.
    Constructor called.
    Volume of Box1: 5.94
    Volume of Box2: 102
    
    展开全文
  • 友元函数,内联函数

    2018-10-13 00:25:52
    类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。 友元可以是一个函数,该函数被称为友元函数...

     

    目录

     

     

    友元函数

    为什么要引入友元函数:

    什么时候使用友元函数:

    怎么使用友元函数:

    友元函数的分类:

    代码如下:

    内联函数:

    为什么要使用内联函数

    内敛函数定义格式

    内联函数注意事项:

    代码展示:


    友元函数

    有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。

    如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend

     

    为什么要引入友元函数:

    在实现类之间数据共享时,减少系统开销,提高效率

    具体来说:为了使其他类的成员函数直接访问该类的私有变量

      即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数

      优点:能够提高效率,表达简单、清晰

      缺点:友元函数破环了封装机制,尽量不使用成员函数,除非不得已的情况下才使用友元函数。



    2、什么时候使用友元函数:

      1)运算符重载的某些场合需要使用友元。

      2)两个类要共享数据的时候



    3、怎么使用友元函数:

    友元函数的参数:

       因为友元函数没有this指针,则参数要有三种情况:

       1、  要访问非static成员时,需要对象做参数;--常用(友元函数常含有参数)

       2、  要访问static成员或全局变量时,则不需要对象做参数

       3、  如果做参数的对象是全局对象,则不需要对象做参数

    友元函数的位置:

    因为友元函数是类外的函数,所以它的声明可以放在类的私有段或公有段且没有区别。


    友元函数的调用:

    可以直接调用友元函数,不需要通过对象或指针



    友元函数的分类:

    根据这个函数的来源不同,可以分为三种方法:

    1、普通函数友元函数:

       a) 目的:使普通函数能够访问类的友元

       b) 语法:声明位置:公有私有均可,常写为公有

                        声明: friend + 普通函数声明

                        实现位置:可以在类外或类中

                        实现代码:与普通函数相同(不加不用friend和类::)

                        调用:类似普通函数,直接调用
     

     

    代码如下:

    #include <iostream>
     
    using namespace std;
     
    class Box
    {
       double width;
    public:
       friend void printWidth( Box box );
       void setWidth( double wid );
    };
    
    // 成员函数定义
    void Box::setWidth( double wid )
    {
        width = wid;
    }
    
    // 请注意:printWidth() 不是任何类的成员函数
    void printWidth( Box box )
    {
       /* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
       cout << "Width of box : " << box.width <<endl;
    }
     
    // 程序的主函数
    int main( )
    {
       Box box;
     
       // 使用成员函数设置宽度
       box.setWidth(10.0);
       
       // 使用友元函数输出宽度
       printWidth( box );
     
       return 0;
    }

     

    内联函数:

     

    C++ 内联函数是通常与类一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。

    对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。

    如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline在调用函数之前需要对函数进行定义。如果已定义的函数多于一行,编译器会忽略 inline 限定符。

    在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符。

     

    为什么要使用内联函数

    在c语言中,宏定义是我们保护效率的一大妙招,(宏:代码处不加验证的简单替代,在编译前将程序中有关字符串替换成宏体)如 defin pi 3.14,用3.14替换pi这个字符在程序运行前。
    但是在c++中,由于私有成员不能存取,宏作用为成员函数就很无用,因此引入了内敛函数。

    内敛函数定义格式


    inline 返回值类型 函数名(形式参数表)
    {//函数体} //即普通函数前,加上inline即可成为内联函数。

    作用:像宏一样展开,因此不需要花费进行参数传递,保存调用状态和返回地址的时间。
    缺点:花费大量空间


    内联函数实际上是一种空间换时间的做法。

    c++类内给出函数体定义的成员函数被默认为内联函数,类外给出函数体的成员函数不是内联函数。

    内联函数注意事项:


    1:内联函数不能含有复杂的分支或循环结构(如switch和whlie)。
    2:递归调用的函数不能定义为内联函数。
    3:内联函数代码不宜过长。
     

    代码展示:

    #include <iostream>
    using namespace std;
    
    inline int Aa(int a,int s){
    
        return (a>s)?a:s;
    }
    int main()
    {
        cout <<Aa(2,3)<<endl;
        cout <<Aa(6,3)<<endl;
        cout <<Aa(72,3)<<endl;
        cout <<Aa(8,3)<<endl;
        return 0;
    }

    输出的结果是:

    3
    6
    72
    8

     

    展开全文
  • 内联函数  概念:以inline修饰的函数叫做内联... 特性:1.Inline是一种用空间换取时间的做法,省去调用函数额外开销,所以代码很长或者有循环/递归函数不适宜使用内联  2.inline对编译器而言只是一个建议,编...

    内联函数

        概念:以inline修饰的函数叫做内联函数,编译是C++编译器会在调用内敛函数的地方展开,没有函数压栈

                   的开销,内联函数提升程序运行的效率

        特性:1.Inline是一种用空间换取时间的做法,省去调用函数额外开销,所以代码很长或者有循环/递归的函数不适宜使用内联

                   2.inline对编译器而言只是一个建议,编译器会自动优化,如果定义为Inline的函数体内有循环或者递归

                      等等,编译器会自动忽略掉内联

                   3.inline必须和函数定义放在一起,才能成为内敛函数,仅仅将inline放在声明前是不起作用的

                   4.定义在类内的成员函数默认定义为内联函数

    注意:在C++中强烈建议使用const代替宏常量,使用const和内联函数在进行编译时不仅进行替换,而且还会进行参数 

               类型检测,提高程序的安全性,内联函数可以是普通函数,也可以是类的成员函数,函数式宏不能作为累的成员函数

     例子:

    class Test
    {
    public:
    	void output();
    };
    inline void Test::output()
    {
    	cout << "my" << endl;
    }

     或者直接在类内定义内联函数

     

    1.宏有什么优缺点?

    优点:1.提高了程序可毒性,同时也方便进行修改;

                2.提高了程序的运行效率,使用带参的宏定义既可以完成函数调用的功能,又能避免函数出栈与

                    入栈操作,减少系统开销,提高运行效率;

      缺点:1.由于是直接嵌入,代码相对多一点             

                 2.参数每次用于宏定义时它们都将重新求值,由于多次求值,带有副作用的参数可能会产生不可预料的结果

                 3.对带参的宏来说,由于是直接替换,不会检查参数是否合法,存在安全隐患

     

    2.宏函数和内联函数的区别

        宏和内联函数都采用了空间换时间的方法,在其调用处进行展开

        1.在预编译时期宏定义在调用处执行替换。在编译时期,内联函数在调用处展开,同时进行参数的类型检查

        2.内联函数是函数,可以像调用普通函数一样调用内联函数。宏定义需要添加很多括号防止歧义,编写复杂

        3.内联函数可以作为类的成员函数,成为类的保护成员或私有成员,当一个表达式涉及到类的保护成员或私有

           成员时,宏就不能实现了(无法将this指针放在合适的位置)

    友元:分为友元函数、友元类

    友元函数:

        友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在

        类中声明,声明需要加上friend关键字

         例子:

    class Date
    {
    	friend void PrintDate(const Date&d);
    public:
    	Date(int year, int month, int day)
    		:_year (year)
    		, _month (month)
    		, _day (day)
    	{}
    	
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    void PrintDate(const Date&d)
    {
    	cout << d._year << "_" << d._month << "_" << d._day << endl;
    }
    int main()
    {
    	Date x(2018, 9, 10);
    	PrintDate(x);
    	return 0;
    }

        特性:1.友元函数可以访问类的私有成员,但不是类的成员函数

                   2.友元函数不能用const修饰

                   3.友元函数可以在类的任何地方声明,不受访问限定符限制

                   4.一个函数可以是多个类的友元函数

                   5.友元函数的调用和普通函数的调用原理相同

    友元类:

        概念:友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员

                在A类定义friend B 说明B类是A类的友元,所以在B的成员函数中可以访问A类对象的私有成员

                也就是说,在A中定义B ,B是A的朋友,在B中可以访问A

    例子:

    class B
    {
    public:
    	B()
    		:_x(100)
    	{}
    private:
    	int _x;
    	friend class A;
    	friend void show();
    };
    class A
    {
    public:
    	A()
    		:_y(200)
    	{}
    	void show(B&b)
    	{
    		cout << b._x << endl;
    		cout << _y << endl;
    	}
    private:
    	int _y;
    
    };
    int main()
    {
    	A a;
    	B b;
    	a.show(b);
    	return 0;
    }

    使用友元优点是提高了程序的运行效率,缺点是破坏了类的封装性和隐藏性

    注意:友元关系不能继承,友元关系是单向的不具有交换性,友元关系不能传递

     

    展开全文
  • 子类调用父类中的友元函数

    千次阅读 2017-12-09 22:22:39
    为此可以通过强制类型转换,将子类的指针或是引用强转为父类的引用或是指针,然后使用转换后的引用或是指针来调用基类中的友元函数。 #include "stdafx.h" #include <iostream> using namespace std; class...
  • //定义类X、Y、Z,函数h(X *),满足: //类X有私有成员i,Y的成员函数g(X *)是X的友元函数,实现对X的成员i加1, //类Z是类X的友元类,其成员函数f(X *)实现对X的成员i加5, //函数h(X *)是X的友元函数,实现对X的...
  • 在C++中,类与C语言中的结构体类似,类与结构体的不同之处便是在其内部多了几个成员函数还有几个访问限定符,访问限定符有public(公共)、protected(保护)、private(私有),而成员函数总的来说共包括六大类,...
  • 内联函数:C++为提高程序运行速度所做的一项改进。... 常规函数调用:执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈(为此保留的内存块),跳到标记函数起点的内存...
  • 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用 2.3. 若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,...
  • 成员函数或友元函数做为线程函数

    千次阅读 2016-10-08 16:58:34
    WIN32线程控制主要实现线程的创建、终止、挂起和恢复等操作,这些操作都... 在启动一个线程之前,必须为线程编写一个全局的线程函数,这个线程函数接受一个32位的LPVOID作为参数,返回一个UINT,线程函数的结构为:
  • 在创建对象时,编译器通过调用构造函数,给对象中各个成员一个合适的初始值 class Date { public: Date(int year, int month, int day) { _year = year; _month = month; _day = d...
  • 友元函数 一,引用 在C语言中,我们了解到函数传递参数的方式有传值和传址。 传值 优点:函数的副作用不会影响到外部的实参 缺点:不能通过修改参数来改变外部实参 ————————————————...
  • // win32Test.cpp : Defines the entry point for the console application. // #include "stdafx.h" ...这样就会形成递归调用。 //使用const,还允许用一个常量对象作为样本,来构造一个新的对象。
  • 友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。  当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句...
  • 在成员函数后面加上const,const修饰this指针所指向的对象,也就是保证调用这个const成员函数的对象在函数体内不会被改变 权限可以缩小,但是不可以放大 **1.**const对象不可以调用非const成员函数 2.非const对象...
  • 友元函数this

    千次阅读 2016-11-21 10:54:58
    关于C++中的友元函数的总结 1.友元函数的简单介绍 1.1为什么要使用友元函数 在实现类之间数据共享时,减少系统开销,提高效率。如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该...
  • 但是,有时需要定义一些函数,这些函数不是类的一部分(注意友元函数不是类的一部分),但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该函数的友元函数。除了友元函数外,还有友元类,两者统称为友元。...
  • 类的内联函数,const修饰的函数,友元函数,静态成员 一.类的内联函数。 内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入...
  • 从下面的单步调试过程可以看出来,Date类成员变量中有一个自定义类型Time时间类,Date日期类的构造函数调完我们自己写的初始化列表后,并不是就执行函数体,而是去调Time的构造函数,从而对自己...
  • 一、类的普通成员函数 普通成员函数本质上是一个包含指向具体对象this指针的普通函数,即c++类的普通成员函数都隐式包含一个指向当前对象的this指针。 class Person { public: Person() { _name = "...
  • 1.const成员函数 2.内联函数 ...在成员函数后面加const,const修饰this指针所指向的对象,也就是保证调用这个const成员函数的对象在函数内不会被改变。 class Date { public : void Display () { cout...
  • 内联函数、友元函数
  • const修饰成员函数:在成员函数后面加const,const修饰指针所指向的对象,也就是说保证调用这个const成员函数的对象在函数内不会被改变。 class Date { public: void Display() { cout&lt;&lt;_year&...
  • 友元函数 创建一个类,让他里面仅仅只有一个私有变量: void Test(const Test&amp; a) { a._a = 1;//可以在友元函数内部直接访问类的私有变量 } class Test { friend void Test(const Test&amp; a);//...
  • 注意:在重载和>>符号时,就必须用到友元函数了,因为在成员函数中会有this指针,而this指针总是第一个参数,而和>>符号需要两个参数,而当是符号时,为了提高代码的可读性,就要把类的对象放在右边,但是this指针却...
  • 在成员函数后面加const, const修饰this指针所指向的对象,也就是保证调用这个const成员函数的对象在函数中 不会被改变 如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员函数, 编译器将...
  • 在C++中友元函数允许在类外访问该类中的任何成员,就象成员函数一样,友元函数用关键字friend说明。 特点 ① 友元函数不是类的成员函数,必须采用全局 ② 友元函数在一定程度上破坏了类的封装性,可以从类...
  • 在成员函数后面加const,const修饰this指针所指向的对象,也就是保证调用这个const成员函数的对象在函数内不会被改变。 #include&amp;amp;amp;amp;amp;lt;iostream&amp;amp;amp;amp;amp;gt; using ...
  • const修饰成员函数 在成员函数后面加const,意味着this指针指向的对象只读。 ...用inline修饰的成员函数是内联函数,当调用内联函数时,C++编译器会在调用出将内联函数展开,而不会重新开辟...
  • 八、友元函数和友元类: 1.情况下,允许特定的非成员函数访问一个类的私有成员,但同时仍然组织一般的访问。 2.友元机制允许一个类将对其非公有成员的访问权限授予制定的函数或者类。 (1)友元的声明以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,672
精华内容 1,468
关键字:

友元函数的递归调用