注意
C++不带.h的是C++的stl库
如< string >是字符串对象的库
<string.h> < cstring >是字符串的函数库,俗称老库
using namespace std;//命名空间
引用返回的好处:
静态成员函数
可以拿类型名加四个点直接访问静态成员
也可以拿对象直接访问静态成员
但是下面这个形式
上面的访问NUM代表静态,下面的Node是Obj嵌套类型
编译器识别区分不出了
必须拿关键字
typename类型名关键字
让编译器知道Node
void Pritn_Student() const
{
typename std::vector<Student>::const_iterator it = studdata.begin();
for (; it != studdata.end(); ++it)
{
cout << it->Id() << " " << it->Name() << " " << it->Sex() << " " << it->Age() << endl;
}
cout << endl;
}
迭代器
常迭代器begin,指向第一个学生,end()返回最后一个学生的后继,两个it不相等,调动对象的id,Name,Sex,Age输出,然后++it, 最后这两个迭代器指到一块了,到末尾了。
auto特点
for(auto x:studdata)
for循环的auto的能力:可以获取studdata容器存储数据的类型,x就是Student类型了,输出的时候,把s1对象拷贝到x上,x就不是指针了。整个是拷贝构造的动作
但是这句代码效率非常低 产生大规模的拷贝
最好的方法如下
void Pritn_Student() const//打印学生//常方法
{
cout << "output 学生信息" << endl;
for(auto const &x: studdata)//常引用
{
x << cout;
cout << endl;
}
cout << endl;
}
此处用到重载<<
重载<<如下:
ostream& operator<<(ostream& out) const
{
out << s_id << " " << s_name << " " << s_sex << " " << s_age;
return out;
}
学生信息管理系统的实现(不完整)
#include<string>
#include<vector>
#include<iostream>
using namespace std;
class Student//学生信息
{
private:
string s_id;//学号
string s_name;//姓名
string s_sex;//性别
int s_age;//年龄
public:
Student() :s_age(0) {}//缺省构造函数,不带参数
Student(const string& id, const string& name, const string& sex, const int age)//构造函数//引用带进来,且不需修改
:s_id(id), s_name(name), s_sex(sex), s_age(age)//构建,带参数的构造函数
{}
~Student() {}//析构函数
//赋值函数和拷贝构造函数暂时不需写
string & Id() { return s_id; }//引用返回,使函数具有双重特性,即可以获取学生id号又可以修改它
const string& Id() const { return s_id; }//常对象调用此方法//使得程序具有通用性
string& Name() { return s_name; }//普通对象调用普通方法,没有普通方法就调用常方法
const string& Name() const { return s_name; }//常对象,不能赋值,可以取值
string& Sex() { return s_sex; }
const string& Sex() const { return s_sex; }
int& Age() { return s_age; }
const int& Age() const { return s_age; }
//通过公有方法改变私有属性
ostream& operator<<(ostream& out) const//重载输出流
{
out << s_id << " " << s_name << " " << s_sex << " " << s_age;
return out;
}
};
class Course//课程类型
{
private:
string c_id;//课程号
string c_name;//课程名
string c_thacher;//任课老师
int credit;//学分
};
class Score
{
private:
string s_id;//学号
string c_id;//课程号
float result;//成绩
};
class StudManage//学生个人信息类实现好之后,要把学生信息放入容器中
{
std::vector<Student> studdata;//学生数值,数组,容器
typename std::vector<Student>::iterator cur;//定义:当前迭代器,typename告诉编译器iterator是类型,不是静态成员
public:
StudManage() {}//缺省构造函数
~StudManage() {}//析构函数
void Add_Student(const Student& s)//添加学生
{
studdata.push_back(s);//尾部添加,vector是数组,尾部添加比较好
}
void Pritn_Student() const//打印学生//常方法
{
cout << "output 学生信息" << endl;//输出学生信息
for(auto const &x: studdata)//常引用
{
x << cout;//使用重载<<
cout << endl;//换行
}
cout << endl;//换行
}
bool Find_Id(const string& id)//查询功能的实现,普通方法,因为后期其他功能需要使用
{
bool res = false;//为了返回bool值,初始化为假
cur = studdata.begin();//指向第一个元素
for (; cur != studdata.end(); ++cur)//使用迭代器查询
{
if (cur->Id() == id)
{
cout << "查询成功" << endl;
res = true;//定义为真
break;//找到了
}
}
return res;//返回真假,根据返回值即可知道是否查询成功
}
bool Del_Student_Id(const string& id)//删除学生功能的实现,根据id号删除
{
bool res = Find_Id(id);//判断是否查找成功
if (res)//如果查询成功
{
studdata.erase(cur);//迭代器功能,删除了数据,迭代器失效了
cur = studdata.end();//迭代器失效了,让指向末尾
}
return res;//返回真假,是否成功删除
}
};
void Add(StudManage& studMan)//添加函数
{
string id, name, sex;
int age;
char ch;
do
{
cout << "请入学生: " << endl;
cin >> id >> name >> sex >> age;
Student s(id, name, sex, age);
studMan.Add_Student(s);
cout<<"是否继续(N/Y)"<<endl;
cin >> ch;
}while(ch == 'y' || ch == 'Y');
cout << "添加完成" << endl;
}
bool Find_Student(StudManage& studMan)//查询函数,对容器查询
{
string id;
cout << "input find student id" << endl;//请输入学生学号
cin >> id;//输入学号
return studMan.Find_Id(id);//调用,学号查询
}
bool Del_Student(StudManage& studMan)//删除函数
{
string id;
cout << "input del student id" << endl;//请输入删除学生的学号
return studMan.Del_Student_Id(id);//调用
}
int MenuStudent()//定义菜单
{
int pos = 0;
cout << "*************************" << endl;
cout << "*1.Add 2.Print*" << endl;
cout << "*3.Find 4.Del *" << endl;
cout << "*5.Updata 0.退出 *" << endl;
cout << "*************************" << endl;
cout << " 请选择" << endl;
cin >> pos;
return pos;
}
int main()//主函数调用,实现学生信息管理系统
{
StudManage studMan;
int pos = 0;//菜单
do
{
pos = MenuStudent();//学生菜单
switch (pos)
{
case 0: cout << "退出" << endl;
case 1: Add(studMan); break;
case 2: studMan.Pritn_Student(); break;
case 3:
if (Find_Student(studMan))
{
cout << "查询成功" << endl;
}
else
{
cout << "查询失败" << endl;
}
break;
case 4: if(Del_Student(studMan))
{
cout << "删除成功" << endl;
}
else
{
cout << "删除失败" << endl;
}
break;
case 5:
if (Find_Student(studMan))
default:
cout << "选择错误!" << endl;
}
} while (pos != 0);//条件
return 0;
}
重点
class String
{
private:
char* str;
String(char* sp, int)
{
str = sp;
}
public:
String(const char* s = nullptr)//构造函数
{
if (s != nullptr)
{
int len = strlen(s);
str = new char[len + 1];
strcpy_s(str, len + 1, s);
}
else
{
str = new char[1];
str[0] = '\0';
}
}
~String()//析构函数
{
if (str != nullptr)
{
delete[]str;
}
str = nullptr;
}
}
深拷贝函数
String(const String& s)//深拷贝
{
int len = strlen(s.str);
str = new char[len + 1];
strcpy_s(str, len + 1, s.str);
}
深赋值语句重载函数
String& operator=(const String& s)//深赋值语句的重载
{
if (this != &s)
{
delete[]str;//释放自己的资源
int len = strlen(s.str);//计算要赋值的字符串的长度
str = new char[len + 1];//申请新的空间
strcpy_s(str, len + 1, s.str);//拷贝
}
return *this;
//s1 = s2;
// s1.str = null s2.str= null;
// s1.str = null s2.str != null;
// s1.str != null, s2.str == null;
// s1.str != null , s2.str != null
}
移动构造函数
String(String&& s) //移动构造
{
str = s.str;
s.str = nullptr;//拥有权的转移
}
移动赋值函数
String& operator=(String&& s)//移动赋值
{
if (this != &s)
{
delete[]str;//释放资源
str = s.str;//指向s.str所拥有的
s.str = nullptr;//s.str置为空
}
return *this;
}
上面这个程序问题出在哪里呢?
s1+s2;发生内存泄漏
构建对象,无论如何str都不为空,最差情况都会含一个\0
减轻编写的压力
return String(sp);
这里调动的是构造函数
因为sp是指针类型 不是右值对象
sp是构造它
构造函数的s指向sp指向的“tulunhello”,s不为空,产生len长度,构建对象,(就是临时对象),内容拷贝进去,返回。但是sp指向的对象还在。“tulunhello"有两个备份。构建的这个对象是将亡值,调用移动赋值。不相等,把s3的str析构掉,把s3的str指向将亡值的这个成员,“tulunhello”,然后把将亡值变为空,return *this,赋值结束,调用析构函数,总的来说就是sp构建的对象没有被析构掉。
更改:
String operator+(const String& s) const
{
int alen = strlen(this->str); // *this
int blen = strlen(s.str); // s;
char* sp = new char[alen + blen + 1];
strcpy_s(sp, alen + 1, this->str);
strcat_s(sp, alen + blen + 1, s.str);
String tmp(sp);
delete[]sp;
return tmp;
}
地址不一样。
析构两次:tmp对象的析构,tmp将亡值对象的析构
私有构造
private:
char* str;
String(char* sp, int)
{
str = sp;
}
String operator+(const String& s) const//s1 s2相加本身不能改变,结果给s3
{
int alen = strlen(this->str); // *this
int blen = strlen(s.str); // s
char* sp = new char[alen + blen + 1];//总长度
strcpy_s(sp, alen + 1, this->str);//给前者(this)先拷贝
strcat_s(sp, alen + blen + 1, s.str);//后者(s.str)拷贝进去
return String(sp, 1);//sp调用构造函数
//无名对象(右值),调用移动赋值函数
}
当我们构建s1,s2,s3对象,s1和s2相加,char* sp = new char[alen + blen + 1];//总长度 动态产生了空间,构建临时对象,临时对象的str指向sp,sp获得的拥有权给当时的临时对象(无名对象),再把无名对象给s3赋值,移动赋值,s3的str指向sp指向的空间,空间转移了。调用析构函数。针对于赋值语句写的私有构造函数
String operator+(const String& s) const
{
int alen = strlen(this->str); // *this
int blen = strlen(s.str); // s;
char* sp = new char[alen + blen + 1];
strcpy_s(sp, alen + 1, this->str);
strcat_s(sp, alen + blen + 1, s.str);
String tmp;
delete[]tmp.str;
tmp.str = sp;
return tmp;
//return String(sp, 1);
}
对象和字符串相加
String operator+(const char* s) const
{
return *this + String(s);
}
字符串和对象相加
String operator+(const char* s, const String& st)
{
return String(s) + st;
}
下面在string类里面进行重载<<
ostream& operator<<(ostream& out) const//实现s3<<cout
{
out << this->str;
return out;
}
下面这个重载函数放在外部,没有this指针,两个参数,cout和s3传进去,然后参数s3调用它的类(String)里的重载函数,也就是调用第一个重载<<函数。
ostream& operator<<(ostream& out, const String& s)//实现cout<<s3<<endl;
{
s << out;
return out;
}
int main()
{
String s1("tulun");
String s2("hello");
String s3;
s3 = s1 + s2;
s3 = s1 + "newdata";
s3 = "newdata" + s1;
//s3 << cout;
cout << s3 << endl;
return 0;
}
int main()
{
String s1("yhping");
String s2(std::move(s1));//移动
String s3("hello");
s3 = s1;
return 0;
}
重载<<的应用例子:
#include<iostream>
using namespace std;
class String
{
private:
char* str;
String(char* sp, int)
{
str = sp;
}
public:
String(const char* s = nullptr)//构造函数
{
if (s != nullptr)
{
int len = strlen(s);
str = new char[len + 1];
strcpy_s(str, len + 1, s);
}
else
{
str = new char[1];
str[0] = '\0';
}
}
~String()//析构函数
{
if (str != nullptr)
{
delete[]str;
}
str = nullptr;
}
String(const String& s)//深拷贝
{
int len = strlen(s.str);
str = new char[len + 1];
strcpy_s(str, len + 1, s.str);
}
ostream& operator<<(ostream& out) const//实现s3<<cout
{
out << this->str;
return out;
}
};
ostream& operator<<(ostream& out, const String& s)//实现cout<<s3<<endl;
{
s << out;
return out;
}
int main()
{
String s1("tulun");
s1<< cout;
cout << s1<< endl;
return 0;
}
运行截图如下
String& operator+=(const String& s)
{
int alen = strlen(this->str); // *this
int blen = strlen(s.str); // s;
char *sp = new char[alen + blen + 1];
strcpy_s(sp, alen + 1, this->str);
strcat_s(sp, alen + blen + 1, s.str);
delete[]this->str;
this->str = sp;
return *this;
}
String& operator+=(const char* s)
{
return *this += String(s);
}
bool operator==(const String& _X) const
{
return strcmp(this->str, _X.str) == 0;
} // s1 == s2; s1.operator=(s2);
bool operator!=(const String& _X) const
{
return !(*this == _X);
}
int main()
{
String s1("tulun");
String s2("hello");
s1 += s2;
s1 += "yhping";
s1 == s2;
return 0;
}