string.h头文件
#ifndef STRING_H_
#include<iostream>
using std::ostream;
using std::istream;
#define STRING_H_
class String
{
private:
char* str;
int len;
static int num_string;//静态类成员,对于所有类对象,该成员数据是共享的
public:
static const int CINLIM = 80;
String(const char* s);
String();
String(const String&);
//复制构造函数和重载赋值运算符是不一样的东西
~String();//在构造函数中使用new来分配内存时,必须在相应的析构函数中使用delete来释放该内存
int length() const { return len; };
String& operator=(const String&);
String& operator=(const char*);
char& operator[](int i);
//利用重载后的下标运算符,可以像数组一样来访问什么位置的元素
const char& operator[](int i) const;
friend bool operator<(const String& st, const String& str2);
friend bool operator>(const String& st1, const String& str2);
friend bool operator==(const String& st, const String& st2);
friend ostream& operator<<(ostream& os, const String& st);
friend istream& operator>>(istream& is, const String& st);
static int HowMany();
};
//在构造函数中使用new时应注意的事项:
//1、如果在构造函数中使用new,则应在析构函数中使用delete
//2、new和delete必须互相兼容
//3、如果有多个构造函数,则必须以相同的方式使用new,要么带[],要么什么都不带
//4、应定义一个复制构造函数,进行深度的复制
//5、应定义一个赋值运算符,进行深度的复制将一个对象复制给另一个对象
//返回引用一般是用来提高运行效率的一种,普通的返回会先生成一个临时变量,在进行赋值
//对象指针--可以将指针初始化为指向已有的对象
//在一下情况下会调用析构函数:1、对象是动态变量2、对象是静态变量3、new创建的要使用delete
#endif
string.cpp文件
#include<cstring>
#include"string1.h"
using std::cout;
using std::cin;
int String::num_string = 0;//初始静态类成员:指出类型,使用作用域解析运算符,不使用关键字static
//静态类成员不能在类声明,因为类声明不会分配内存,只是告诉如何分配内存,不能在同文件中声明,会在引入同文件时,生成多个版本
//注意只有枚举和const整数型,才可以在类声明中进行初始化
int String::HowMany()
{
return num_string;
}
String::String(const char* s)
{
len = std::strlen(s);
str = new char[len + 1];
std::strcpy(str, s);
num_string++;
}
String::String()
{
len = 4;
str = new char[1];
str[0] = '\0';
num_string++;
}
String::String(const String& st)
{
num_string++;
len = st.len;
str = new char[len + 1];
std::strcpy(str, st.str);
}
String::~String()
{
--num_string;
delete[]str;
}
String& String::operator=(const String& st)
{
if (this == &st)
return *this;
delete[]str;
len = st.len;
str = new char[len + 1];
std::strcpy(str, st.str);
return *this;
}
String& String::operator=(const char* s)
{
delete[]str;
len = std::strlen(s);
str = new char[len + 1];
std::strcpy(str, s);
return *this;
}
char& String ::operator[](int i)
{
return str[i];
}
const char& String::operator[](int i)const
{
return str[i];
}
bool operator<(const String& st1, const String& st2)
{
return (std::strcmp(st1.str, st2.str) < 0);
}
bool operator>(const String& st1, const String& st2)
{
return st2 < st1;
}
bool operator==(const String& st1, const String& st2)
{
return (std::strcmp(st1.str, st2.str) == 0);
}
ostream& operator<<(ostream& os, const String& st)
{
os << st.str;
return os;
}
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;
}
类和动态内存分配.cpp文件
#include<iostream>
#include"string.h"
//通常最好是在程序运行时确定诸如使用多少内存等问题---oop式思想
//静态类成员有一个特点:无论创建多少个对象,程序都只创建一个静态类变量副本(只有一个)
//这里做一下总结5大特殊成员函数:默认构造函数、默认析构函数、复制构造函数、复制运算符、地址运算符
//在前面讲过只有一个参数的构造函数被用作转换函数
//如果没有提供这些函数,系统会在你要调用的时候自动生成该函数,但这些对于工作远远不够,还是要自己定义
/*如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数,以复制指向的数据,而不是指针,这种被称作深度复制,成员复制或浅复制只是复制该内容的地址*/
//进行类中的赋值时,会先分配一个新的内存,如果地址不同,则要先把原来的地方释放掉
//以后要改掉习惯,要用nullptr来表示空指针,c是NULL
//静态类成员函数————只能访问静态数据成员-static,并且要使用类名+作用域解析运算符来进行调用
int main()
{
}