zoukankan      html  css  js  c++  java
  • C++ inline与operator


    title: C++ inline与operator
    date: 2020-03-10
    categories: c++
    tags: [c++]

    inline修饰符,operator关键字

    1.inline修饰符-内联函数

    1.1为何需要inline

    在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。
    在系统下,栈空间是有限的,大量调用函数会造成栈溢出

    inline char* dbtest(int a) {
        return (i % 2 > 0) ? "奇" : "偶";
    } 
     
    int main()
    {
       int i = 0;
       for (i=1; i < 100; i++) {
           printf("i:%d    奇偶性:%s /n", i, dbtest(i));    
       }
    }
    

    每个 for 循环的内部任何调用 dbtest(i) 的地方都换成了 (i%2>0)?"奇":"偶",这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗。

    1.2 inline使用限制

    inline 的使用是有所限制的,inline 只适合涵数体内代码简单的涵数使用,不能包含复杂的结构控制语句例如 while、switch,并且不能内联函数本身不能是直接递归函数(即,自己内部还调用自己的函数)。

    1.3 inline仅是一个对编译器的建议

    inline 函数仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思,它如果认为函数不复杂,能在调用点展开,就会真正内联

    1.4 建议 inline 函数的定义放在头文件中

    因为内联函数要在调用点展开,所以编译器必须随处可见内联函数的定义,要不然就成了非内联函数的调用了。所以,这要求每个调用了内联函数的文件都出现了该内联函数的定义。因此,将内联函数的定义放在头文件里实现是合适的,省却你为每个文件实现一次的麻烦。

    1.5 类中的成员函数与inline

    定义在类中的成员函数默认都是内联的,如果在类定义时就在类内给出函数定义,那当然最好。如果在类中未给出成员函数定义,而又想内联该函数的话,那在类外要加上 inline,否则就认为不是内联的。

    class A
    {
        public:void Foo(int x, int y) {  } // 自动地成为内联函数
    }
    
    // 头文件
    class A
    {
        public:
        void Foo(int x, int y);
    }
     
    // 定义文件
    inline void A::Foo(int x, int y){}   //注意 A::
    

    1.6 inline 是一种"用于实现的关键字"

    关键字 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 与函数定义体放在一起
    

    1.7 慎用 inline

    内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。
    如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。
    以下情况不宜使用内联:
    (1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
    (2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如"偷偷地"执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了 inline 不应该出现在函数的声明中)。

    2 operator

    参考:https://blog.csdn.net/liitdar/article/details/80654324

    2.1 operator简介

    operator 是C++的一个关键字,它和运算符(如=)一起使用,表示一个运算符重载函数,在理解时可将operator和运算符(如operator=)视为一个函数名。

    使用operator重载运算符,是C++扩展运算符功能的方法。使用operator扩展运算符功能的原因如下:

    使重载后的运算符的使用方法与重载前一致。
    扩展运算符的功能只能通过函数的方式实现(实际上,C++中各种“功能”都是由函数实现的)。

    2.2 使用operator的原因

    对于C++提供的所有操作符,通常只支持对于基本数据类型和标准库中提供的类的操作,而对于用户自己定义的类,如果想要通过该操作符实现一些基本操作(比如比较大小,判断是否相等),就需要用户自己来定义关于这个操作符的具体实现了。

    比如,我们要设计一个名为“person”的类,现在要判断person类的两个对象p1和p2是否一样大,我们设计的比较规则是按照其年龄来比较,那么,在设计person类的时候,就可以通过对操作符“”进行重载,来使用操作符“”对对象p1和p2进行比较了(根据前面的分析,实际上比较的内容应该是person类中的数据成员“age”)。

    我们上面说的对操作符“”进行重载,说是“重载”,是由于编译器在实现操作符“”功能的时候,已经为我们提供了这个操作符对于一些基本数据类型的操作支持,只不过由于现在该操作符所操作的内容变成了我们自定义的数据类型(如class),而默认情况下,该操作符是不能对我们自定义的class类型进行操作的,所以,就需要我们通过重载该操作符,给出该操作符操作我们自定义的class类型的方法,从而达到使用该操作符对我们自定义的class类型进行运算的目的。

    2.3 how

    实现一个操作符重载的方式通常分为两种情况:

    将操作符重载实现为类的成员函数;
    操作符重载实现为非类的成员函数(即全局函数)。

    2.3.1 将操作符重载实现为类的成员函数

    在类体中声明(定义)需要重载的操作符,声明方式跟普通的成员函数一样,只不过操作符重载函数的名字是“关键字 operator +一个C++预定义的操作符”

        bool operator==(const person& ps)const
        {
            if (this->age == ps.age)
            {
                return true;
            }
            return false;
        }
    
    class person
    {
    private:
        int age;
    public:
        person(int nAge)
        {
            this->age = nAge;
        }
     
        bool operator==(const person& ps)const
        {
            if (this->age == ps.age)
            {
                return true;
            }
            return false;
        }
    };
    

    通过inline和const的学习,建议改成

    class person{
    private:
        int age;
        public:
        person(int a){
           this->age=a;
        }
       inline bool operator == (const person &ps) const;
    };
    
    // 实现
    inline bool person::operator==(const person &ps) const
    {
      if (this->age==ps.age)
         return true;
      return false;
    }
    
    
        person p1(10);
        person p2(10);
        
        if (p1 == p2)
    

    2.3.2 操作符重载实现为非类的成员函数(即全局函数)

    对于全局重载操作符,代表左操作数的参数必须被显式指定。

    class person
    {
    public:
        int age;
    };
     
    // 左操作数的类型必须被显式指定
    // 此处指定的类型为person类
    bool operator==(person const& p1 ,person const& p2)
    {
        if (p1.age == p2.age)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
     
    int main()
    {
        person p1;
        person p2;
        p1.age = 18;
        p2.age = 18;
     
        if (p1 == p2)
        {
            cout << "p1 is equal with p2." << endl;
        }
        else
        {
            cout << "p1 is NOT equal with p2." << endl;
        }
     
        return 0;
    }
    

    2.3.4 操作符重载的方式选择

    如果一个重载操作符是类成员,那么只有当与它一起使用的左操作数是该类的对象时,该操作符才会被调用;而如果该操作符的左操作数确定为其他的类型,则操作符必须被重载为全局函数;

    C++要求'='、'[]'、'()'、'->'操作符必须被定义为类的成员操作符,把这些操作符通过全局函数进行重载时会出现编译错误

    如果有一个操作数是类类型(如string类),那么对于对称操作符(比如==操作符),最好通过全局函数的方式进行重载。

    2.3.5 操作符重载的限制

    实现操作符重载时,需要注意:

    重载后操作符的操作数至少有一个是用户定义类型;
    不能违反原来操作数的语法规则;
    不能创建新的操作符;
    不能重载的操作符包括(以空格分隔):sizeof . .* :: ?: RTTI类型运算符
    =、()、[]、以及 ->操作符只能被类的成员函数重载

    (1) 只有C++预定义的操作符集中的操作符才可以被重载;
    C++可以被重载的运算符表

    (2)对于内置类型的操作符,它的预定义不能被改变,应不能为内置类型重载操作符,如,不能改变int型的操作符+的含义;

    (3) 也不能为内置的数据类型定义其它的操作符;

    (4) 只能重载类类型或枚举类型的操作符;

    (5) 重载操作符不能改变它们的操作符优先级;

    (6) 重载操作符不能改变操作数的个数;

    (7) 除了对( )操作符外,对其他重载操作符提供缺省实参都是非法的;

    最后https://www.cnblogs.com/ZY-Dream/p/10068993.html 这里更详细

    https://blog.csdn.net/liitdar/article/details/80656156 operator=

  • 相关阅读:
    2月4日进度
    每日总结3-6
    每日总结3-5
    每日总结3-4
    每日总结3-2
    本周计划
    本周计划
    假期每日总结2-13
    假期每日总结2-12
    假期每日总结2-11
  • 原文地址:https://www.cnblogs.com/lqerio/p/13485191.html
Copyright © 2011-2022 走看看