灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2457回复:0

[C++技术]一个简单的string类Str

楼主#
更多 发布于:2012-09-06 11:33


看到《accelerated c++》的一个string类的简单实现,学到了许多操作符和类型转换的东西,记录下来,备忘。。。
Str.h
#include <iostream>
#include <algorithm>
#include <cstring>
#include "Vec.h"

class Str
{
    //友元函数有与成员函数一样的访问权限,而且可以放到类定义中的任意位置
    friend std::istream; operator>> (std::istream;,Str;);
public:
    typedef Vec<char>:ize_type size_type;

    Str() { } //默认构造函数
    Str(size_type n,char c):data(n,c) {} //有连个参数(数目,字符)构造数目的字符的字符串
    Str(const char* p){ //从字符串常量转化为string的构造函数
        std::copy(p,p+std:trlen(p),std::back_inserter(data));
        //std::cout<<"测试1"<<std::endl;
    }
    //从迭代器b和e之间的元素创建一个string
    template <class In> Str(In b,In e){
        std::copy(b,e,std::back_inserter(data));
    }

    //operator[]索引操作符
    char; operator[] (size_type i) { return data; }
    const char; operator[] (size_type i) const { return data; }
    
    //连接操作符 ①s=s+s1;②s+=s1
    Str; operator += (const Str; s)
    {
        std::copy(s.data.begin(),s.data.end(),std::back_inserter(data));
        return *this;
    }
    //定义大小
    size_type size() const { return data.size(); }
    
private:
    Vec<char> data;
};

//输入-输出操作符
//判断一个函数时候应该是成员函数,我们前面章节有个标准:看看这个操作是否会影响对象的状态
//输入操作当然改变对象了,应该把它当做Str的成员函数吗?
//不可以,原因:对于一个二元操作符(如cin>>s),左操作数总是与第一个参数绑定,但是对于
//成员操作符函数来说,第一个参数隐式的为此成员函数的对象,所以cin>>s表示的应该是
//cin中得成员函数>>,但是istream是没有定义权限的。所以我们要想使cin>>s成立,就必须
//决定:输入操作符必须是一个非成员函数,同理,输入也是
std::istream; operator>> (std::istream;,Str;);
std::ostream; operator<< (std::ostream;,const Str;);
Str operator + (const Str; ,const Str; );//加法运算符的重载(不会改变任何值,所以类外定义)
Str.cpp
#include "Str.h"
using namespace std;

//我们调用Str::operator[]-->Vec::operator[];类似调用s.size()-->Vec对象的size
ostream; operator<< (ostream; os,const Str; s)
{
    for (Str:ize_type i=0;i!=s.size();++i)
    {
        os<<s;
    }
    return os;
}
istream; operator>> (istream; is,Str; s)
{
    s.data.clear(); //清空数据www.atcpu.com
    char c; //一个字符一个字符的读取
    while (is.get(c);;isspace(c))
    {//一直读取字符,知道不是空字符,或者读取操作结束
        ;
    }
    if (is) //判断是否读取结束
    {
        do
        {
            s.data.push_back(c);
        } while (is.get(c);;!isspace(c));
        if (is) //判断是否读取结束
        {
            is.unget(); //此时多读取了一个空白字符,要放回到输入流中,防止下次出错
        }
    }
    return is;
}
//加法
Str operator + (const Str; s,const Str; t )
{
    Str rhs=s;
    rhs+=t;
    return rhs;
}

另外,再说明两点:
1. 二元操作符问题
+=操作符,改变了它的左操作数,所以应该定义为类Str的成员;
注意:如果一个类支持类型转换,那么把二元操作符定义为非成员函数是一个很好的习惯。
如果一个操作符是一个类的成员,那么这个操作符的左操作数就不能事自动类型转换的结果。
非成员操作符的左操作数以及任意操作符的右操作数,都遵循与普通函数参数相同的规则:操作数可以是任意类型,只要它能转换层参数类型。
+操作符,应该为非成员函数,应为如果是成员函数,左右操作数就不对称了(右操作数可以自动类型转换,左操作数不可以)
+操作符的返回应该是左值,不应该是。(c++ primer解释:算术运算符通常产生一个新值,该值是两个操作数的计算结果,它不同于任一操作数,并且在一个局部变量的计算中返回对那个变量的是一个运行时错误。)
2. 类型转换操作符(conversion operator)(从类到其他类型,与构造函数相反)
定义:这种操作符可以说明如何把这个类的对象转换为目标类型。类型转换操作符必须被定义为类的成员。格式:operator 目标类型,如 operator double
事实上,我们每次编写隐式的检测一个istream对象的值的循环式,都会使用这种类型转换操作符。如,while(cin)
原理:标准库定义了从istream到void*的类型转换istream operator void*() 。void*可以转化为bool型,所以上例成立。

延伸:为什么istream不定义operator bool 直接把cin转换为bool?
考虑 int x; cin<<x;(正确为cin>>x;)  此时,operator bool 直接把cin转换为bool,生成的的bool值会转换成int类型,然后把这个值左移x位,最后丢弃生成的结果。
注:通过定义转换为void*的操作,而不是转换为算术类型,标准库既可以使一个istream对象能用作一个条件式,也可以阻止它被用作一个算术值。


喜欢0 评分0
游客

返回顶部