下面的代码来自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. Java程序猿的JavaScript学习笔记(8——jQuery选择器)

    计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...

  2. HTML DOM 创建与修改

    修改 HTML 元素 修改 HTML DOM 意味着许多不同的方面: 改变 HTML 内容 改变 CSS 样式 改变 HTML 属性 创建新的 HTML 元素 删除已有的 HTML 元素 改变事件(处 ...

  3. 《Linux内核设计与实现》内存管理札记

    1.页 芯作为物理页存储器管理的基本单元,MMU(内存管理单元)中的页表,从虚拟内存的角度来看,页就是最小单位. 内核用struct page结构来标识系统中的每个物理页.它的定义例如以下: flag ...

  4. 怎样用Excel自动排成绩

    经常需要做表格,排成绩名次总是笨笨的一个一个填,费时又费力,终于找到了解决的办法%>_<%(不要嘲笑我了(✿◡‿◡)),原来就是一个名叫RANK的函数,还在苦逼地自己输的小伙伴们,快来看吧 ...

  5. js中||和&&的用法

    在js中&&.||不一定都是用来判断一个表达式的逻辑值是true.false,更多的是用来依据真值或者假值执行相应操作! a() && b() :如果执行a()后返回t ...

  6. 5.6.3.8 fromCharCode()方法

    String构造函数本身还有一个静态方法:fromCharCode().这个方法的任务是接收一或多个字符编码,然后将它们转换成一个字符.从本质上来看,这个方法与实例方法charCodeAt()执行的是 ...

  7. 一次搞懂 Assets Pipeline 转载自http://gogojimmy.net/2012/07/03/understand-assets-pipline/

    Assets Pipeline 是 Rails 3.1 一個重要的功能,一直並沒有很去了解其特性,但因為最近都在寫前端的東西在 assets pipeline 的東西上跌跌撞撞了不少次(尤其在 dep ...

  8. 浅谈RFID电子标签封装技术

    1RFID技术概述 1.1RFID技术概念 RFID是RadioFrequencyIdentification的缩写,即射频识别技术,俗称电子标签.RFID射频识别是一种非接触式的自动识别技术,它通过 ...

  9. PC游戏编程(入门篇)(前言写的很不错)

    PC游戏编程(入门篇) 第一章 基石 1. 1 BOSS登场--GAF简介 第二章 2D图形程式初体验 2.l 饮水思源--第一个"游戏"程式 2.2 知其所以然一一2D图形学基础 ...

  10. android 百度最新地图sdk包怎么去除 放大缩小按钮

    // 隐藏缩放控件 int childCount = mMapView.getChildCount(); View zoom = null; ; i < childCount; i++) { V ...