C++之重载String ----- 构造函数、复制控制、重载操作符
2014-09-29 01:02
246 查看
本博文我们通过重新实现String类 来说明构造函数,复制控制,重载操作符。(本文末尾有完整代码以及测试结果)
一、构造函数(包括析构函数):
1:默认构造函数;
2:用户自己定义的构造函数
注意:当用户自己定义时,也要明确显示默认构造函数,这是因为,当我们没有定义自己的构造函数时,编译器会为我们自动合成一个,而我们定义了构造函数时,编译器默认构造函数改为我们自己定义的。这时就有可能出现错误;
3:析构函数;
具体声明与实现,代码如下:
二、复制控制(见上个博文);
三:重载运算符;
1)、 输入输出:
由于 输入输出流不可复制也不能复制,因此,形参和返回值只能为 引用 类型。
注意:为了与io标准库一致,操作符应接受i/ostream&作为第一个形参,对类类型const对象的引用作为第二个形参,并返回对 i/ostream 形参的引用。
输入时,要注意检查输入的内容是否合法;(注意inline的作用)
具体声明与实现 如以下代码:
2)、赋值操作符与复合赋值操作符的重载:
赋值操作符 = 必须是类的成员函数。
一般而言, = 、+= 应返回做操作数的引用。
具体声明与实现如下代码:
3)、加法运算符(+):
我们最好将 + 运算符声明为friend函数,因为若果声明为成员函数,则第一个参数 默认为本对象,这就可能限制 + 运算符的作用范围。
注意:这里我们用上述的 += 实现 +,这样可以不必 创建和赊销一个临时变量来保存+ 的结果;加法操作符不改变操作数的状态,所以我们将 操作数声明为 const对象的引用, 而 它产生并返回一个新的对象,该对象初始化为 第一个参数 const String &s1的副本。
实现如下:
4)、关系运算符:
实现如下:
5)、下标操作符 与 swap函数
下标操作符 最好 重载两个,因为 String 有 非const 和 const型。
而const型 是不允许修改的。
完整代码如下:
String.cpp:
main.cpp:
测试结果如下:
一、构造函数(包括析构函数):
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
相关文章推荐
- c++OOP之复制控制 ------复制构造函数、赋值重载、析构
- C++中复制构造函数与重载赋值操作符
- C++继承与构造函数、复制控制
- 【c++primer——】第13章复制控制——01深入理解复制构造函数
- c++ premier -- 复制控制与重载操作符
- C++ 第13章 复制控制---复制构造函数、赋值操作符、析构函数
- c++ 初学 构造函数和复制控制
- 批注:C++中复制构造函数与重载赋值操作符总结:默认浅拷贝,带指针的需要深拷贝
- C++语法基础--复制控制--复制构造函数 ,赋值操作符 ,析构函数
- C++复制控制
- 复制控制:复制构造函数、赋值操作符、析构函数
- C++复制控制的问题
- [原创]关于C++的构造函数, 复制构造函数 和 operator =
- 原来C++中struct也有构造函数与析构函数,也可以有访问类型控制
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
- C++结构体:默认构造函数,复制构造函数,重载=运算符
- 由C++复制控制想到
- C++复制控制
- [原创]关于C++的构造函数, 复制构造函数 和 operator =
- C++学习笔记--复制构造函数