您的位置:首页 > 编程语言 > C语言/C++

C++之重载String ----- 构造函数、复制控制、重载操作符

2014-09-29 01:02 246 查看
本博文我们通过重新实现String类 来说明构造函数,复制控制,重载操作符。(本文末尾有完整代码以及测试结果)

一、构造函数(包括析构函数):

1:默认构造函数;

2:用户自己定义的构造函数

注意:当用户自己定义时,也要明确显示默认构造函数,这是因为,当我们没有定义自己的构造函数时,编译器会为我们自动合成一个,而我们定义了构造函数时,编译器默认构造函数改为我们自己定义的。这时就有可能出现错误;

3:析构函数;

具体声明与实现,代码如下:

声明部分:
String();
String(const char*s);   //by user
String(const String &s); //by user
~String();
实现部分:
String::String()
:str_(new char[1])
{ *str_ = 0; }

String::String(const char*s)
:str_(new char[strlen(s)+1])
{
cout << "constructed by user" << endl;
::strcpy(str_, s);
}

String::String(const String &s)//复制构造函数
:str_(new char[s.size()+1])
{
cout << "copy" << endl;
::strcpy(str_, s.str_);
}

String::~String()//将delete[] 放入析构函数中是为了防止悬浮指针
{
cout << "~construct" << endl;
delete[] str_;
}


二、复制控制(见上个博文);
三:重载运算符;

1)、 输入输出:

由于 输入输出流不可复制也不能复制,因此,形参和返回值只能为 引用 类型。

注意:为了与io标准库一致,操作符应接受i/ostream&作为第一个形参,对类类型const对象的引用作为第二个形参,并返回对 i/ostream 形参的引用。

输入时,要注意检查输入的内容是否合法;(注意inline的作用)

具体声明与实现 如以下代码:

声明:
friend std::ostream &operator<<(std::ostream &os, const String &s);
friend std::istream &operator>>(std::istream &is, String &s);
实现:
inline std::ostream &operator<<(std::ostream &os, const String &s)
{
os << s.str_ ;
return os;//no copy, no assignment;return reference
}
inline std::istream &operator>>(std::istream &is, String &s)
{
char tmp[1024];
if(is >> tmp)//注意要检查错误
s.str_ = tmp;
return is;
}


2)、赋值操作符与复合赋值操作符的重载:
赋值操作符 = 必须是类的成员函数。

一般而言, = 、+= 应返回做操作数的引用。

具体声明与实现如下代码:

声明:
String& operator=(const char*s);
String& operator=(const String &s);
String& operator+=(const char*s);
String& operator+=(const String &s);
实现:
//赋值时必须判断左右操作数是否相同;否则delete[]将会把“自己”删除
String& String::operator=(const char*s)
{
cout << "assignment" << endl;
if(str_ != s)
{
delete[] str_;
str_ = new char[strlen(s)+1];
::strcpy(str_ ,s);
}
return  *this;
}

String& String::operator=(const String &s)
{
cout << "assignment" << endl;
if(this != &s)//attention
{
delete[]str_;
str_ = new char[s.size()+1];
::strcpy(str_, s.str_);
}
return *this;
}
//复合赋值的步骤:
//产生一个临时变量,将左右操作数复制于其中;
//删除原来的成员, 将临时变量copy至成员中
String& String::operator+=(const char*s)
{
cout <<"complex assignment" << endl;
char *st = new char[size()+strlen(s) +1];
::strcpy(st, str_);
::strcat(st, s);

delete[]str_;//attention
str_ = st ;

return *this;
}
String& String::operator+=(const String &s)
{
cout << "complex assignment" << endl;
char *st = new char[size()+s.size()+1];
::strcpy(st, str_);
::strcat(st, s.str_);

delete[]str_;//attention
str_ = st ;

return *this;
}


3)、加法运算符(+):
我们最好将 + 运算符声明为friend函数,因为若果声明为成员函数,则第一个参数 默认为本对象,这就可能限制 + 运算符的作用范围。

注意:这里我们用上述的 += 实现 +,这样可以不必 创建和赊销一个临时变量来保存+ 的结果;加法操作符不改变操作数的状态,所以我们将 操作数声明为 const对象的引用, 而 它产生并返回一个新的对象,该对象初始化为 第一个参数 const String &s1的副本。

实现如下:

声明;
friend String operator+(const String &s1, const String &s2);
friend String operator+(const String &s1, const char *str);
friend String operator+(const char *str , const String &s1);
实现:
String operator+(const String &s1, const String &s2)
{
String s(s1);
s += s2;
return s;
}

String operator+(const String &s1, const char *str)
{
String s(s1);
s += str;
return s;
}

String operator+(const char *str, const String &s1)
{
String s(s1);
s += str;
return s;
}


4)、关系运算符:

实现如下:

声明:
friend bool operator>(const String &s1, const String &s2);
friend bool operator>=(const String &s1, const String &s2);
friend bool operator<(const String &s1, const String &s2);
friend bool operator<=(const String &s1, const String &s2);
friend bool operator==(const String &s1, const String &s2);
friend bool operator!=(const String &s1, const String &s2);
实现:
bool operator>(const String &s1, const String &s2)
{
return ::strcmp(s1.str_, s2.str_)>0 ;
}
bool operator>=(const String &s1, const String &s2)
{
return !(s1 < s2);
}
bool operator<(const String &s1, const String &s2)
{
return !((s1 > s2)|| s1 == s2);
}
bool operator<=(const String &s1, const String &s2)
{
return !(s1 > s2) ;
}
bool operator==(const String &s1, const String &s2)
{
return ::strcmp(s1.str_, s2.str_)==0;
}
bool operator!=(const String &s1, const String &s2)
{
return !(s1 == s2);


5)、下标操作符 与 swap函数
下标操作符 最好 重载两个,因为 String 有 非const 和 const型。

而const型 是不允许修改的。

声明:
void swap(String &other);
char &operator[](size_t index);
const char operator[](size_t index)const;

size_t size()const
{ return strlen(str_); }
const char *c_str()const
{ return str_; }
实现:
char &String::operator[](size_t index)
{
return str_[index];
}

const char String::operator[](size_t index)const
{
return str_[index];
}

void String::swap(String &other)
{
std::swap(str_, other.str_);


完整代码如下:

//String.h
#ifndef STRING_H_
#define STRING_H_

#include <iostream>
#include <string.h>

//含有指针的类
class String
{
friend std::ostream &operator<<(std::ostream &os, const String &s);
friend std::istream &operator>>(std::istream &is, String &s);
friend String operator+(const String &s1, const String &s2);
friend String operator+(const String &s1, const char *str);
friend String operator+(const char *str , const String &s1);
friend bool operator>(const String &s1, const String &s2);
friend bool operator>=(const String &s1, const String &s2);
friend bool operator<(const String &s1, const String &s2);
friend bool operator<=(const String &s1, const String &s2);
friend bool operator==(const String &s1, const String &s2);
friend bool operator!=(const String &s1, const String &s2);
public:
String();
String(const char*s);   //by user
String(const String &s); //by user
~String();

String& operator=(const char*s);
String& operator=(const String &s);
String& operator+=(const char*s);
String& operator+=(const String &s);

void swap(String &other);
char &operator[](size_t index);
const char operator[](size_t index)const;

size_t size()const
{ return strlen(str_); }

const char *c_str()const
{ return str_; }

void print()const;

private:
char *str_;
};
inline std::ostream &operator<<(std::ostream &os, const String &s)
{
os << s.str_ ;
return os;//no copy, no assignment;return reference
}
inline std::istream &operator>>(std::istream &is, String &s)
{
char tmp[1024];
if(is >> tmp)//注意要检查错误
s.str_ = tmp;
return is;
}

#endif


String.cpp:

//String.cpp
#include "String.h"

#include <string.h>
#include <iostream>
using namespace std;

String::String()
:str_(new char[1])
{ *str_ = 0; }

String::String(const char*s)
:str_(new char[strlen(s)+1])
{
cout << "constructed by user" << endl;
::strcpy(str_, s);
}

String::String(const String &s)//复制构造函数
:str_(new char[s.size()+1])
{
cout << "copy" << endl;
::strcpy(str_, s.str_);
}

String::~String()//将delete[] 放入析构函数中是为了防止悬浮指针
{
cout << "~construct" << endl;
delete[] str_;
}
//赋值时必须判断左右操作数是否相同;否则delete[]将会把“自己”删除
String& String::operator=(const char*s)
{
cout << "assignment" << endl;
if(str_ != s)
{
delete[] str_;
str_ = new char[strlen(s)+1];
::strcpy(str_ ,s);
}
return  *this;
}

String& String::operator=(const String &s)
{
cout << "assignment" << endl;
if(this != &s)//attention
{
delete[]str_;
str_ = new char[s.size()+1];
::strcpy(str_, s.str_);
}
return *this;
}

//复合赋值的步骤:
//产生一个临时变量,将左右操作数复制于其中;
//删除原来的成员, 将临时变量copy至成员中
String& String::operator+=(const char*s)
{
cout <<"complex assignment" << endl;
char *st = new char[size()+strlen(s) +1];
::strcpy(st, str_);
::strcat(st, s);

delete[]str_;//attention
str_ = st ;

return *this;
}
String& String::operator+=(const String &s)
{
cout << "complex assignment" << endl;
char *st = new char[size()+s.size()+1];
::strcpy(st, str_);
::strcat(st, s.str_);

delete[]str_;//attention
str_ = st ;

return *this;
}

String operator+(const String &s1, const String &s2)
{
String s(s1);
s += s2;
return s;
}

String operator+(const String &s1, const char *str)
{
String s(s1);
s += str;
return s;
}

String operator+(const char *str, const String &s1)
{
String s(s1);
s += str;
return s;
}

bool operator>(const String &s1, const String &s2)
{
return ::strcmp(s1.str_, s2.str_)>0 ;
}
bool operator>=(const String &s1, const String &s2)
{
return !(s1 < s2);
}
bool operator<(const String &s1, const String &s2)
{
return !((s1 > s2)|| s1 == s2);
}
bool operator<=(const String &s1, const String &s2)
{
return !(s1 > s2) ;
}
bool operator==(const String &s1, const String &s2)
{
return ::strcmp(s1.str_, s2.str_)==0;
}
bool operator!=(const String &s1, const String &s2)
{
return !(s1 == s2);
}

char &String::operator[](size_t index)
{
return str_[index];
}

const char String::operator[](size_t index)const
{
return str_[index];
}

void String::swap(String &other)
{
std::swap(str_, other.str_);
}
void String::print()const
{
cout << str_ << endl;
}


main.cpp:

#include "String.h"
#include <iostream>
#include <string.h>
#include <assert.h>
#include <unistd.h>
using namespace std;

int main(int argc, const char *argv[])
{
String s;
s.print();

String s2("hello");
s2.print();
cout <<s2.size() << endl;
cout << s2.c_str() << endl;
/*
String s3;
cin >> s3;
cout << s3 << endl; //munmap_chunk()->invalid pointer
*/
String s4;   //String s4 = "hello world" init
s4 = "hello world";
cout << s4 << endl;

String s5;
s5 = s4 ;
cout << s5 << endl;

assert(s5 == s4);
assert(s5 != s2);
assert(s5 >= s2);
assert(s5 > s2);
assert(s2 < s5);
assert(s2 <= s5);

String t1 ;
t1 = "beij";
t1 += "shangh";
cout << t1 << endl;

String t2;
t2 = "shenzh";
t1 += t2 ;
cout << t1 << endl;

t1[0]= 'A';
cout << t1 << endl;
/*
const String t3 ="wnager"; // error const->k
t3[0]='l';
cout << t3 << endl;
*/
String u1 ,u2;
u1 = s2;
u2 = "wow";

u1 = u2 + " my god";
cout << u1 << endl;

u1 = t2 + u2 ;
cout << u1 << endl;

cout << "before:" ;
cout << s4 << "  " << u2 << endl;

cout << "swap"<< endl;
u2.swap(s4);
cout << "after:";
cout << s4 << "  " << u2 << endl;

return 0;
}


测试结果如下:

//test result
test@ubuntu:~/xiaofei/0926overloading$ ./a.out

constructed by user
hello
5
hello
assignment
hello world
assignment
hello world
assignment
complex assignment
beijshangh
assignment
complex assignment
beijshanghshenzh
Aeijshanghshenzh
assignment
assignment
copy
complex assignment
assignment
~construct
wow my god
copy
complex assignment
assignment
~construct
shenzhwow
before:hello world  wow
swap
after:wow  hello world
~construct
~construct
~construct
~construct
~construct
~construct
~construct
~construct
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: