main.cpp
#include "MyString.h"
//智能指针的意义是你new一个空间,是指针指向这个空间,不用在调用delete去回收指针指向的空间,系统会自己帮我们回收
int main()
{
//一般指针开辟空间
int *p = new int;
//智能指针开辟空间
//anto_ptr<int>等价于int * ,其本质为指针的类型,<>括号里存储的为指针开辟空间存储的数据类型,ptr为指针名,(new int)表明其在堆中开辟空间,返回给指针ptr
//也可以这样理解,auto_ptr<>即为一种模板类,(new int)的地址返回值为构造函数的参数,ptr即为一个对象,不过这个对象为指针
auto_ptr<int> ptr1;
auto_ptr<int> ptr2(new int);
*ptr2 = 10;
//下面一段代码ptr3为Test *类型的指针,auto_ptr<Test>等价于Test * ,(new Test(10))是表示调用类Test的有参构造函数同时在堆中开辟空间,并把空间地址返回给指针ptr
auto_ptr<Test> ptr3(new Test(10));
Test *t = new Test(10);
(*t).function();//*是直接取指针指向的对象,但.的运算优先级高于* ,因此需要加小括号
delete t;
MyAutoPtr ptr4(new Test(100));
//注意,这里的ptr4是MyAutoPtr类型的对象,并不是new出来的Test类型对象的指针,ptr4.ptr才为new出来的Test类型对象的指针
//因此对象ptr4如果直接想调用它内部指针指向对象的函数,则需要重写->操作符
//这儿其实执行完ptr4->返回指针ptr,此时应该就没有了->操作符,但这儿其实还留有->操作符给返回的指针使用,难道是因为->只与前面参数有关,所有与前面有关的操作符在执行完后这个操作符仍要继续使用一次???
ptr4->function();//先写出代码式子,在根据式子重写操作符,等价于ptr4.operator->();
(*ptr4).function();//这时应返回指针指向对象的本身
cout << endl << endl << endl;
Test1 t1(1);
Test2 t2(2, t1);
string s1 = "123";
s1 = "1212";//重载了=操作符
string s2 = "456";
cout << "s1+s2=" << s1 + s2 << endl;//重载了+操作符
//cin >> s1[1];//重载了>>操作符
s1[1] = 'q';//重载了[]操作符
if (s1 == s2)//重载了==操作符
{
}
if (s1 != s2)//重载了!=操作符
{
}
//int a, b;
//cin >> a >> b;//cin也可以连续输入
/*
char *c = NULL;
char *d = NULL;
strcpy(c, d);//不可以对指向为空的指针进行拷贝
*/
char *c = new char[3];
const char *d = "111";
char e[3];
char f[3] = { 0 };
//strlen()函数是遇'\0'结束的,在new来的空间时,因为最后一位不是'\0'因此strlen()函数仍会继续向下相加,直到遇到第一个'\0'为止才停止计算,因此用strlen计算数组是不准确的,最好只用来计算字符串的长度
cout << "strlen(c)=" << strlen(c) << endl;//结果是未知的
cout << "strlen(d)=" << strlen(d) << endl;//结果是3
cout << "strlen(e)=" << strlen(e) << endl;//结果是未知的
cout << "sizeof(c)=" << sizeof(c) << endl;//结果是0,因为数组内都是'\0',strlen()函数遇'\0'结束
//strcpy()与strlen()不同,strcpy()函数在不是字符串的时候就会停止,而strlen()只会在遇到'\0'才停止
MyString m1;
MyString m2("xuhaoxuan");
MyString m3;
MyString m4("xuqiang ");
m3 = m1 + m2;
cout << "111=" << m3;
cout << "222=" << m4 + m2;
return 0;
}
MyString.cpp
#include "MyString.h"
MyString::MyString()
{
this->len = 0;
this->str = NULL;
}
MyString::MyString(int len)
{
if (len = 0)
{
this->len = 0;
this->str = NULL;
}
else
{
this->len = len;
this->str = new char[len];
}
}
MyString::MyString(const char *str)
{
if (str == NULL)
{
this->len = 0;
this->str = NULL;
}
else
{
this->len = strlen(str) + 1;
this->str = new char[len];
strcpy(this->str, str);
}
}
MyString::MyString(const MyString &s)
{
if (s.str == NULL)
{
this->len = 0;
this->str = NULL;
}
else
{
this->len = s.len;
this->str = new char[len];
strcpy(this->str, s.str);
cout << "copy function=" << this->str << endl;
}
}
MyString &MyString::operator=(const MyString &s)//类型不用加作用域,只有类里的成员方法才需要加类名作用域,记住operator+等这些操作符重载函数也是成员方法,一定需要带上类名作用域
{
if (s.str == NULL)
{
this->len = 0;
this->str = NULL;
}
else
{
this->len = s.len;
if (this == &s)
{
return *this;
}
if (this->str != NULL)
{
delete[] this->str;
}
this->str = new char[len];
strcpy(this->str, s.str);
}
return *this;
}
char &MyString::operator[](int index)
{
return this->str[index];
}
bool MyString::operator==(const MyString &s)
{
int key = strcmp(this->str, s.str);//相等返回0,this->str大于s.str返回正数,this->str小于s.str返回负数
if (key == 0)
{
return true;
}
else
{
return false;
}
}
bool MyString::operator!=(const MyString &s)
{
int key = strcmp(this->str, s.str);
if (key == 0)
{
return false;
}
else
{
return true;
}
}
char *MyString::getStr()const
{
return str;
}
MyString MyString::operator+(const MyString &s)
{
MyString temp;
if (this->str == NULL && s.str == NULL)
{
return temp;
}
if (this->str == NULL && s.str != NULL)
{
temp.len = s.len;
cout << "temp.len=" << temp.len << endl;
temp.str = new char[temp.len];
strcpy(temp.str, s.str);
cout << "s.str=" << s.str << endl;
cout << "temp.str=" << temp.str << endl;
return temp;
}
if (this->str != NULL && s.str == NULL)
{
temp.len = this->len;
temp.str = new char[temp.len];
strcpy(temp.str, this->str);
return temp;
}
if (this->str != NULL && s.str != NULL)
{
temp.len = this->len + s.len;
temp.str = new char[temp.len];//new开辟出来的空间里面的值是随机的,并不是0
memset(temp.str, 0, temp.len);
strcpy(temp.str, this->str);
char *point = temp.str;
while (1)
{
if ( *point == '\0')
{
break;
}
point++;
}
strcpy(point, s.str);
return temp;
}
return temp;
}
MyString::~MyString()
{
if (this->str != NULL)
{
delete[] str;//不能释放NULL
}
}
ostream &operator<<(ostream &out, const MyString &s)
{
if (s.getStr() == NULL)//因为在这个方法作用域内s都是不可改变的,所以在这期间所有用到s对象的函数都需要用const修饰
{
return out;
}
else
{
out << s.getStr() << endl;
return out;
}
}
istream &operator>>(istream &in, const MyString &s)
{
in >> s.str;
return in;
}
//下面三段代码的写法是错误的,在返回引用的时候,变量a就可以改变,但这时a在test()函数中是不可改变的,这两个相冲突,所以在函数中被const修的变量是绝对不可以返回引用的
/*
int &test(const int a)
{
return a;
}
*/
MyString.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <memory>//为系统自带的智能指针头文件,是用智能指针需要调用这个头文件
#include <string>//为系统自带的字符串类,string类里重写了很多操作符
using namespace std;
class MyString
{
public:
friend istream &operator>>(istream &in, const MyString &s);//编译器会自己帮我们去包含这个头文件的.cpp文件找到这些函数的定义
MyString();
MyString(int len);//创建一个长度为len的字符串
MyString(const char *str);//这是给定字符串的构造函数,但并不是拷贝构造
MyString(const MyString &another);
char *getStr()const;
MyString &operator=(const MyString &s);
char &operator[](int index);
bool operator==(const MyString &s);
bool operator!=(const MyString &s);
MyString operator+(const MyString &s);
~MyString();
private:
int len;
char *str;
};
//new开辟出来的内存空间如果没有被delete,则将会在程序运行结束时操作系统自己回收,并不是在重启电脑时释放,网上很多讲解都是错误的!!!
class Test
{
public:
Test(int a)
{
this->a = a;
}
void function()
{
cout << "-----------------------------------" << endl;
}
//一个对象在栈空间时,当进程结束时会自动调用析构函数回收这个对象
//一个对象在堆空间时,你不使用delete去显式的释放这个对象,那么当进程结束时,不会调用析构函数,因此凡是new出来的对象,都需要手动的delete
//在堆区间开辟出来的对象只有析构函数是不主动触发的,只有调用delete删除这个对象空间时,才会触发析构函数
//注意这儿的delete与析构函数内部的delete完全不同,析构函数内部的delete是为了释放有类内部指针开辟的堆空间,而外部的delete是为了释放new出来的对象,但使用智能指针开辟对象,则就不需要手动释放了
~Test()
{
cout << "~Test()..." << endl;
}
private:
int a;
};
class MyAutoPtr
{
public:
MyAutoPtr(Test *ptr)
{
this->ptr = ptr;
}
Test *operator->()
{
return this->ptr;
}
Test operator*()
{
return *ptr;
}
~MyAutoPtr()
{
if (this->ptr != NULL)//因为ptr为void *类型,即万能指针,因此delete ptr时不会去调用类型Test的析构函数,它只是回去调void类型的析构函数,显然没有,所以不会触发Test类型的析构函数
{
delete ptr;
}
}
private:
Test * ptr;
};
class Student
{
public:
Student(int id, char *name)//这儿应有一个隐式的:name(),调用的可能是默认构造函数???
{
this->id = id;
this->name = name;//一般的赋值应用strcpy函数,但我们调用了string类,并建立其对象,这个对象里其实有char *类型的指针,会开辟一个空间存储字符串,也可能是“=”“->”操作符重载,和智能指针一模一样???
}
private:
int id;
string name;//string这个类即为char *的封装类,可以直接指向字符串,里面还重写了很多操作符,使字符串操作更简单便捷
};
class Test1
{
public:
Test1(int a)
{
cout << "Test1()..." << endl;
this->a = a;
}
Test1(const Test1 &t)//const看右边,只看一位,是谁就修饰谁,&看左边,可以看多为,是谁就修饰谁
{
cout << "Test1 copy function..." << endl;
this->a = t.a;
}
int getA()
{
return this->a;
}
Test1 &operator=(const Test1 &t)
{
cout << "Test1 equal==============================" << endl;
this->a = a;
return *this;
}
private:
int a;
};
class Test2
{
public:
Test2(int a, Test1 t100) :t(1000)//构造函数形参里的Test t100为调用拷贝构造函数构建的,构造函数初始化列表是调用构造函数建立的,这儿创建的对象即为这个类里的this->t
{
cout << "Test2->Test1 t.a=" << t.getA() << endl;
this->a = a;
this->t = t;//这儿调用的是=号操作符重载,并不是拷贝构造函数
cout << "Test2 t.a=" << this->t.getA() << endl;
}
private:
Test1 t;
int a;
};
istream &operator>>(istream &in, const MyString &s);
ostream &operator<<(ostream &out, const MyString &s);