下面的代码来自c++ primer plus第5版第12章,书中代码写的非常好:

// string1.h -- fixed and augmented string class definition
#include <iostream>
using std::ostream;
using std::istream; #ifndef STRING1_H_
#define STRING1_H_
class String
{
private:
char * str; // pointer to string
int len; // length of string
static int num_strings; // number of objects
static const int CINLIM = ; // cin input limit
public:
// constructors and other methods
String(const char * s); // constructor
String(); // default constructor
String(const String &); // copy constructor
~String(); // destructor
int length () const { return len; }
// overloaded operator methods
String & operator=(const String &);
String & operator=(const char *);
char & operator[](int i);
const char & operator[](int i) const;
// overloaded operator friends
friend bool operator<(const String &st, const String &st2);
friend bool operator>(const String &st1, const String &st2);
friend bool operator==(const String &st, const String &st2);
friend ostream & operator<<(ostream & os, const String & st);
friend istream & operator>>(istream & is, String & st);
// static function
static int HowMany();
};
#endif
num_strings 主要是为了统计对象创建的个数.
cpp文件:
// string1.cpp -- String class methods
#include <cstring> // string.h for some
#include "string1.h" // includes <iostream>
using std::cin;
using std::cout; // initializing static class member int String::num_strings = ; // static method
int String::HowMany()
{
return num_strings;
} // class methods
String::String(const char * s) // construct String from C string
{
len = std::strlen(s); // set size
str = new char[len + ]; // allot storage
std::strcpy(str, s); // initialize pointer
num_strings++; // set object count
} String::String() // default constructor
{
len = ;
str = new char[];
str[] = '\0'; // default string
num_strings++;
} String::String(const String & st)
{
num_strings++; // handle static member update
len = st.len; // same length
str = new char [len + ]; // allot space
std::strcpy(str, st.str); // copy string to new location
} String::~String() // necessary destructor
{
--num_strings; // required
delete [] str; // required
} // overloaded operator methods // assign a String to a String
String & String::operator=(const String & st)
{
if (this == &st)
return *this;
delete [] str;
len = st.len;
str = new char[len + ];
std::strcpy(str, st.str);
return *this;
} // assign a C string to a String
String & String::operator=(const char * s)
{
delete [] str;
len = std::strlen(s);
str = new char[len + ];
std::strcpy(str, s);
return *this;
} // read-write char access for non-const String
char & String::operator[](int i)
{
return str[i];
} // read-only char access for const String
const char & String::operator[](int i) const
{
return str[i];
} // overloaded operator friends bool operator<(const String &st1, const String &st2)
{
return (std::strcmp(st1.str, st2.str) < );
} bool operator>(const String &st1, const String &st2)
{
return st2.str < st1.str;
} bool operator==(const String &st1, const String &st2)
{
return (std::strcmp(st1.str, st2.str) == );
} // simple String output
ostream & operator<<(ostream & os, const String & st)
{
os << st.str;
return os;
} // quick and dirty String input
istream & operator>>(istream & is, String & st)
{
char temp[String::CINLIM];
is.get(temp, String::CINLIM);
if (is)
st = temp;
while (is && is.get() != '\n') //  丢弃多余的字符
continue;
return is;
}

代码有许多值得注意的地方:

1.为什么构造函数里面是

str = new char[1];
str[0] = '\0';
而不是
str=new char;
上面2中方式分配的内存量相同,区别在于前者与析构函数兼容,而后者不兼容。析构函数含有如下代码:
delete[] str;
delete[] 与使用new【】初始化的指针和空指针都兼容,因此对于下面的代码:
str = new char[1];
str[0] = '\0';
可修改为
str=0;//set str to the null pointer

对于以其他方式初始化的指针,使用delete[] 删除,结果是不确定的:

char words[15]="ab";

char *p=words;

char *p2=new char;

char *p3;

delete[] p1; //undefined,so don't do it //会产生run time error

delete[] p2;//undefined,so don't do it

delete[] p3;//undefined,so don't do it 会产生run time error.

上面几种方式都不正确。

2.为什么我们要2次重载:

// read-write char access for non-const String
char & String::operator[](int i)
{
return str[i];
}

// read-only char access for const String
const char & String::operator[](int i) const
{
return str[i];
}

是因为如果没有重载常量的[],下面的代码将出错:

const String s("hello");

cout<<a[1];

元素是s是常量,而上述方法无法确保不修改数据。

所以在重载时,c++将区分常量和非常量函数的特征标

有了上述的重载后,

const string s("helloo");

cin>>s[1];就会报错。

istream的get函数有许多重载版本:

single character (1)
  int get();
  istream& get (char& c);
c-string (2)
  istream& get (char* s, streamsize n);
  istream& get (char* s, streamsize n, char delim);
stream buffer (3)
  istream& get (streambuf& sb);
  istream& get (streambuf& sb, char delim);

cin.get()读取单个字符并返回,http://www.cplusplus.com/reference/istream/istream/get/

可不可以将构造函数换成:

String()

{

str="default string";

len=strlen(str);

}

答:不可以,没有使用new[]来初始化str,对默认对象调用析构函数时,使用delete【】来释放,对不是使用new初始化的指针使用

delete,其结果将是不确定的,并可能是有害的。

在构造函数中使用new应注意的问题

使用new来初始化对象的指针成员时必须要特别小心,具体地说,应该是这样:

1.如果在构造函数中使用new来初始化成员指针,则应在析构中调用delete

2,new和delete必须相互兼容,new对于delete,new[]对于delete[]。

3.如果有多个构造函数,则必须以相同的方式使用new,要么带中括号,要么都不带。因为只有一个析构函数,因此所有的构造函数都必须与他兼容。不过,可以在一个构造函数中使用new来初始化指针,而在另一个构造函数中将指针初始化为空(null或0,这是

因为delete(无论是带【】还是不带【】)都可以用于空指针

ostream & operator<<(ostream & os, const String & st) 
可以可以不返回引用?
答:绝对不可以
cout一般都可以链式操作cout<<s<<s2;
如果不返回引用,如果返回类型为ostream,将要求ostream类的复制构造函数,而ostream没有任何公有的复制构造函数。幸运的是,
返回一个指向cout的引用不会带来任何问题。
如果不写成引用,编译不通过。报错:
无法访问 private 成员(在“std::basic_ios<_Elem,_Traits>”类中声明)
我们在xiobase文件中科院看到:
private:
ios_base& __CLR_OR_THIS_CALL operator=(const ios_base& _Right)
 private: ios_base(const ios_base&);
显然,拷贝构造函数与复制操作符都声明为私有。 因此,重载操作符应该如下: ostream& operator<<(ostream &out , CA &ca) istream也是如此。

测试:

这是书本的测试:

// sayings1.cpp -- using expanded String class
// compile with string1.cpp
#include <iostream>
#include "string1.h"
const int ArSize = ;
const int MaxLen =;
int main()
{
using std::cout;
using std::cin;
using std::endl;
String name;
cout <<"Hi, what's your name?\n>> ";
cin >> name; cout << name << ", please enter up to " << ArSize
<< " short sayings <empty line to quit>:\n";
String sayings[ArSize]; // array of objects
char temp[MaxLen]; // temporary string storage
int i;
for (i = ; i < ArSize; i++)
{
cout << i+ << ": ";
cin.get(temp, MaxLen);
while (cin && cin.get() != '\n')
continue;
if (!cin || temp[] == '\0') // empty line?
break; // i not incremented
else
sayings[i] = temp; // overloaded assignment
}
int total = i; // total # of lines read cout << "Here are your sayings:\n";
for (i = ; i < total; i++)
cout << sayings[i][] << ": " << sayings[i] << endl; int shortest = ;
int first = ;
for (i = ; i < total; i++)
{
if (sayings[i].length() < sayings[shortest].length())
shortest = i;
if (sayings[i] < sayings[first])
first = i;
}
cout << "Shortest saying:\n" << sayings[shortest] << endl;;
cout << "First alphabetically:\n" << sayings[first] << endl;
cout << "This program used "<< String::HowMany()
<< " String objects. Bye.\n"; return ;
}

这是我的测试;

#include"String.h"
#include<cassert>
#include<string> int main()
{ //copy constrtor
String s1("abc");
cout<<s1<<endl; String s2(s1);
cout<<s2<<endl; // operator=(const char* s);
s1="helloworld";
cout<<s1<<endl;
// operator=(const String & other);
String s3("youcan");
s1=s3;
cout<<s1<<endl; //调用赋值构造函数
String s4="dddd";
cout<<s4<<endl;
cout<<s1.howMany()<<endl;//输出4 String s5="helloworld";
cout<<s5[]<<endl;
s5[]='z';
cout<<s5<<endl;
const String s6("const");
cout<<s6[]<<endl; }

上面的全都来自c++ primer plus这本书。

STL string 模拟的更多相关文章

  1. 深入剖析 linux GCC 4.4 的 STL string

    转自: 深入剖析 linux GCC 4.4 的 STL string 本文通过研究STL源码来剖析C++中标准模板块库std::string运行机理,重点研究了其中的引用计数和Copy-On-Wri ...

  2. 格式字符串分配stl::string

    代码非常easy,不解释,直接在代码: #include <cstdio> #include <cstdarg> #include <iostream> using ...

  3. 浅谈C++ STL string容器

    浅谈C++ STL string容器 本篇随笔简单讲解一下\(C++STL\)中\(string\)容器的使用方法及技巧. string容器的概念 其实\(string\)并不是\(STL\)的一种容 ...

  4. C++标准模板库Stand Template Library(STL)简介与STL string类

    参考<21天学通C++>第15和16章节,在对宏和模板学习之后,开启对C++实现的标准模板类STL进行简介,同时介绍简单的string类.虽然前面对于vector.deque.list等进 ...

  5. 转C++之stl::string写时拷贝导致的问题

    前几天在开发某些数据结构到文件的 Dump 和 Load 功能的时候, 遇到的一个 bug . [问题复现] 问题主要出在 Load 过程中,从文件读取数据的时候, 直接使用 fread 的去操作 s ...

  6. stl string

    10.2.1 STL的string 1String概念 ²  string是STL的字符串类型,通常用来表示字符串.而在使用string之前,字符串通常是用char*表示的.string与char*都 ...

  7. 洛谷 P1739 表达式括号匹配【STL/stack/模拟】

    题目描述 假设一个表达式有英文字母(小写).运算符(+,-,*,/)和左右小(圆)括号构成,以"@"作为表达式的结束符.请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返 ...

  8. [转载] C++ STL string的Copy-On-Write技术

    原文: http://coolshell.cn/articles/12199.html stl的string是经过严格优化的, 深入理解对以后编程过程中应用string非常有益处, 感谢左耳朵耗子的精 ...

  9. [转] 深入剖析 linux GCC 4.4 的 STL string

    本文通过研究STL源码来剖析C++中标准模板块库std::string运行机理,重点研究了其中的引用计数和Copy-On-Write技术. 平台:x86_64-redhat-linux gcc ver ...

随机推荐

  1. SQL Server索引进阶:第一级,索引简介

    这个并不是我翻译的,全文共有15篇,但我发现好多网站已经不全,所以自己整理. 原文地址: Stairway to SQL Server Indexes: Level 1, Introduction t ...

  2. 经典mssql语句大全

    一.基础 1.说明:创建数据库CREATE DATABASE database-name 2.说明:删除数据库drop database dbname3.说明:备份sql server--- 创建 备 ...

  3. objective-C学习笔记(九)ARC

    ARC叫自动引用计数Automatic Reference Counting.针对堆上的对象,管理对象的创建和释放. 哪些对象受ARC管理: OC对象指针 Block指针 使用_attribute_( ...

  4. MYSQL—加写锁,加读锁,解锁

    链接地址:http://blog.sina.com.cn/s/blog_7fa2bcf50101j1lu.html 表级锁: 加写锁:          lock   tables   table_n ...

  5. USACO Seciton 5.4 Canada Tour(dp)

    因为dp(i,j)=dp(j,i),所以令i>j. dp(i,j)=max(dp(k,j))+1(0<=k<i),若此时dp(i,j)=1则让dp(i,j)=0.(因为无法到达此状态 ...

  6. JAVA语言规范和API网址

    Java语言规范: http://docs.oracle.com/javase/specs/ Java API: http://docs.oracle.com/javase/8/docs/api/in ...

  7. css中z-index属性(标签层叠次序)

    定义和用法 z-index 属性设置元素的堆叠顺序.拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面. 注释:元素可拥有负的 z-index 属性值. 注释:Z-index 仅能在定位元素上奏 ...

  8. Linux必学的60个命令【转载】

    Linux提供了大量的命令,利用它可以有效地完成大量的工 作,如磁盘操作.文件存  [转载地址]http://blog.chinaunix.net/uid-16728139-id-3154272.ht ...

  9. 关于 free() 函数用法的若干疑问

    <C语言参考手册>中关于 free() 函数有如下描述. (1)free() 函数的原型 void free(void *ptr); (2)free 函数对以前由 malloc.callo ...

  10. 怪兽z主机标准版视频测试。

    我的淘宝店很早就开张了,但是一直没有好好打理,这次给大家带来的是本店所售一款主机的视频测试. CPU:AMD -A10 6700 主板:映泰Hi-Fi A88S3E 内存条:正品金士顿骇客游戏神条 机 ...