zoukankan      html  css  js  c++  java
  • C++解析(19):函数对象、关于赋值和string的疑问

    0.目录

    1.函数对象

    2.重载赋值操作符

    3.string类

    4.小结

    1.函数对象

    编写一个函数:

    • 函数可以获取斐波那契数列每项的值
    • 每调用一次返回一个值
    • 函数可根据需要重复使用

    实现功能:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int fib()
    {
        static int a0 = 0;
        static int a1 = 1;
        
        int ret = a1;
        
        a1 = a0 + a1;
        a0 = ret;
        
        return ret;
    }
    
    
    int main()
    {
        for(int i=0; i<10; i++)
        {
            cout << fib() << endl;
        }
        
        cout << endl;
        
        for(int i=0; i<5; i++)
        {
            cout << fib() << endl;
        }
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    1
    1
    2
    3
    5
    8
    13
    21
    34
    55
    
    89
    144
    233
    377
    610
    

    存在的问题——函数一旦开始调用就无法重来

    • 静态局部变量处于函数内部,外界无法改变
    • 函数为全局函数,是唯一的,无法多次独立使用
    • 无法指定某个具体的数列项作为初始值

    函数对象:

    • 使用具体的类对象取代函数
    • 该类的对象具备函数调用的行为三个字
    • 构造函数指定具体数列项的起始位置
    • 多个对象相互独立的求解数列项

    函数调用操作符(( )):
    只能通过类的成员函数重载
    可以定义不同参数的多个重载函数

    最终解决方案——把类的对象当作函数使用:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Fib
    {
        int a0;
        int a1;
    public:
        Fib()
        {
            a0 = 0;
            a1 = 1;
        }
        
        Fib(int n)
        {
            a0 = 0;
            a1 = 1;
            
            for(int i=2; i<=n; i++)
            {
                int t = a1;
                
                a1 = a0 + a1;
                a0 = t;
            }
        }
        
        int operator () ()
        {
            int ret = a1;
        
            a1 = a0 + a1;
            a0 = ret;
            
            return ret;
        }
    };
    
    int main()
    {
        Fib fib;
        
        for(int i=0; i<10; i++)
        {
            cout << fib() << endl;
        }
        
        cout << endl;
        
        for(int i=0; i<5; i++)
        {
            cout << fib() << endl;
        }
        
        cout << endl;
        
        Fib fib2(10);
        
        for(int i=0; i<5; i++)
        {
            cout << fib2() << endl;
        }
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    1
    1
    2
    3
    5
    8
    13
    21
    34
    55
    
    89
    144
    233
    377
    610
    
    55
    89
    144
    233
    377
    

    2.重载赋值操作符

    什么时候需要重载赋值操作符?编译器是否提供默认的赋值操作

    • 编译器为每个类默认重载了赋值操作符
    • 默认的赋值操作符仅完成浅拷贝
    • 当需要进行深拷贝时必须重载赋值操作符
    • 赋值操作符拷贝构造函数有相同的存在意义

    示例:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class Test
    {
        int* m_pointer;
    public:
        Test()
        {
            m_pointer = NULL;
        }
        Test(int i)
        {
            m_pointer = new int(i);
        }
        Test(const Test& obj)
        {
            m_pointer = new int(*obj.m_pointer);
        }
        Test& operator = (const Test& obj)
        {
            if( this != &obj )
            {
                delete m_pointer;
                m_pointer = new int(*obj.m_pointer);
            }
            
            return *this;
        }
        void print()
        {
            cout << "m_pointer = " << hex << m_pointer << endl;
        }
        ~Test()
        {
            delete m_pointer;
        }
    };
    
    int main()
    {
        Test t1 = 1;
        Test t2;
        
        t2 = t1;
        
        t1.print();
        t2.print();
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    m_pointer = 0x252f010
    m_pointer = 0x252f030
    

    (在C语言中支持自赋值,于是C++为了兼容C语言,也得支持自赋值。于是在重载赋值操作符的时候,也得处理自赋值的情况。)

    问题分析:

    一般性原则:
    重载赋值操作符必然需要实现深拷贝!!!

    编译器默认提供的函数:

    3.string类

    下面的代码输出什么?为什么?

    示例:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
        string s = "12345";
        const char* p = s.c_str();
            
        cout << p << endl;     
            
        s.append("abced");  // p 成为了野指针
            
        cout << p << endl;     
    
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    12345
    12345
    

    问题分析:

    下面的程序输出什么?为什么?

    示例:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
        const char* p = "12345";
        string s = "";
        
        s.reserve(10);
        
        // 不要使用 C 语言中的方式操作 C++ 中的字符串
        for(int i=0; i<5; i++)
        {
            s[i] = p[i];
        }
        
        cout << s << endl;
        
        for(int i=0; i<5; i++)
        {
            cout << s[i] << endl;
        }
        
        return 0;
    }
    

    运行结果为空:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    
    1
    2
    3
    4
    5
    

    问题分析:

    改进后:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
        const char* p = "12345";
        string s = "";
        
        s = p;
        
        cout << s << endl;
        
        return 0;
    }
    

    运行结果为:

    [root@bogon Desktop]# g++ test.cpp
    [root@bogon Desktop]# ./a.out 
    12345
    

    4.小结

    • 函数调用操作符(( ))是可重载的
    • 函数调用操作符只能通过类的成员函数重载
    • 函数调用操作符可以定义不同参数的多个重载函数
    • 函数对象用于在工程中取代函数指针
    • 在需要进行深拷贝的时候必须重载赋值操作符
    • 赋值操作符拷贝构造函数有同等重要的意义
    • string类通过一个数据空间保存字符数据
    • string类通过一个成员变量保存当前字符串的长度
    • C++开发时尽量避开C语言中惯用的编程思想
  • 相关阅读:
    使用用Ghost制作的win2k3和winxp文件具有相同的SID的解决办法
    64 bits Windows 7 使用 regsvr32 的註冊方式(转)
    怎么实现用户匿名访问web,但数据库要用Windows集成验证方式(数据库和web服务器分别在两台机器上)
    为什么按照微软给定的匿名配置Web 同步最终造成创建订阅的步骤总是失败?但改为需要身份验证就行了
    How to edit Team Build Types
    利用WhiteHose一步步建立分布式系统的框架(二)创建LDD步骤
    发现:InfoPath 2007 Training Labs地址
    在MSF中怎么区分易混淆的工作项类型:Bug、风险和问题(我个人的理解)
    RGB Colour Map
    How to distinguish Design time or Running time in Mobile cusotmer Contorl(the NetCF2.0 is different to NetCF1.0)
  • 原文地址:https://www.cnblogs.com/PyLearn/p/10085642.html
Copyright © 2011-2022 走看看