STL string 模拟
下面的代码来自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 模拟的更多相关文章
- 深入剖析 linux GCC 4.4 的 STL string
转自: 深入剖析 linux GCC 4.4 的 STL string 本文通过研究STL源码来剖析C++中标准模板块库std::string运行机理,重点研究了其中的引用计数和Copy-On-Wri ...
- 格式字符串分配stl::string
代码非常easy,不解释,直接在代码: #include <cstdio> #include <cstdarg> #include <iostream> using ...
- 浅谈C++ STL string容器
浅谈C++ STL string容器 本篇随笔简单讲解一下\(C++STL\)中\(string\)容器的使用方法及技巧. string容器的概念 其实\(string\)并不是\(STL\)的一种容 ...
- C++标准模板库Stand Template Library(STL)简介与STL string类
参考<21天学通C++>第15和16章节,在对宏和模板学习之后,开启对C++实现的标准模板类STL进行简介,同时介绍简单的string类.虽然前面对于vector.deque.list等进 ...
- 转C++之stl::string写时拷贝导致的问题
前几天在开发某些数据结构到文件的 Dump 和 Load 功能的时候, 遇到的一个 bug . [问题复现] 问题主要出在 Load 过程中,从文件读取数据的时候, 直接使用 fread 的去操作 s ...
- stl string
10.2.1 STL的string 1String概念 ² string是STL的字符串类型,通常用来表示字符串.而在使用string之前,字符串通常是用char*表示的.string与char*都 ...
- 洛谷 P1739 表达式括号匹配【STL/stack/模拟】
题目描述 假设一个表达式有英文字母(小写).运算符(+,-,*,/)和左右小(圆)括号构成,以"@"作为表达式的结束符.请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返 ...
- [转载] C++ STL string的Copy-On-Write技术
原文: http://coolshell.cn/articles/12199.html stl的string是经过严格优化的, 深入理解对以后编程过程中应用string非常有益处, 感谢左耳朵耗子的精 ...
- [转] 深入剖析 linux GCC 4.4 的 STL string
本文通过研究STL源码来剖析C++中标准模板块库std::string运行机理,重点研究了其中的引用计数和Copy-On-Write技术. 平台:x86_64-redhat-linux gcc ver ...
随机推荐
- [Docker]初次接触
Docker 初次接触 近期看了不少docker介绍性文章,也听了不少公开课,于是今天去官网逛了逛,发现了一个交互式的小教程于是决定跟着学习下. 仅仅是把认为重点的知识记录下来,不是非常系统的学习和笔 ...
- iOS 面试题:OC基本概念题
1.什么是类和对象? 类是一组具有同样特征和功能的事物的抽象 对象描写叙述了一个物体的特征和行为实现 类是对象的抽象 对象是类的实例 2.OC中定义类,创建对象,使用对象. OC中定义类分为接口部分, ...
- Android应用开发基础篇(14)-----自定义标题栏
一.概述 每一个应用程序默认的标题栏(注意与状态栏的区别)只有一行文字(新建工程时的名字),而且颜色.大小等都是固定的,给人的感觉比较单调.但当程序需要美化的时候,那么修改标题栏是就是其中一项内容,虽 ...
- Android 动画animation 深入分析
转载请注明出处:http://blog.csdn.net/farmer_cc/article/details/18259117 Android 动画animation 深入分析 前言:本文试图通过分析 ...
- Undefined symbols for architecture xxx
解决方法: "Build Settings"->"Linking"->"Other Linker Flags" add the ...
- 在Oracle 11g中用看Oracle的共享内存段---------IPCS
很早之前,在一次讲课了,用了命令ipcs,发现oracle的共享内段好小,如下: oracle@mydb ~]$ ipcs -a ------ Shared Memory Segments ----- ...
- IOS本地化。
1,项目名本地化 点击项目,蓝色图标->info 最下面+号,添加chinese本地化. Supporting Files->infoPlist.strings 下会有两个文件,有一个是设 ...
- Oracle SQL篇(一)null值之初体验
从我第一次正式的写sql语句到现在,已经超过10年的时间了.我写报表,做统计分析和财务对账,我一点点的接触oracle数据库,并尝试深入了解.这条路,一走就是10年,从充满热情,到开始厌 ...
- 帝国cms让当前栏目显示不同样式(图文)
在使用帝国cms制作栏目导航条时,我们可能会需要根据当前栏目,使当前栏目样式不同. 如图: 此类导航,源代码一般为 <li>全站首页</li> <li class=&qu ...
- 在SQL2005中部署CLR 程序集
原文 在SQL2005中部署CLR 程序集 有关于CLR函数的用途和用法,请了解 SQL Server CLR 极速入门,启用.设计.部署.运行 http://www.yongfa365.com/It ...