1.特殊的成员函数
1.1构造结构
定义对象时,自动调用,用于初始化
1.2析构函数
对象销毁时,自动调用,用于析构
1.3复制函数
默认的复制函数,仅仅只是浅拷贝,obj1=obj2是执行
1.4拷贝构造
默认拷贝构造,仅仅只是浅拷贝,用一个对象去初始化另一个对象,构造拷贝定义的对象不会调用构造函数,西药在开背构造函数中给他分配空间
//例如 :A a2=a1; Aa2(a1);
int i;
int j;
i=j;//赋值函数
int i=j;//拷贝构造
调用的函数不一样
默认的函数是不是没有缺点呢?不是,默认的赋值与拷贝构造都是浅拷贝。如果只是改变val的值,可以使用浅拷贝。但是,一旦维护的数据有指针,那么就会出现问题。
浅拷贝需要屏蔽析构函数,因为a1,a2,指向同以前取余,会析构两次,报错。实际上,delete第一次就已经会换系统了,系统会重新分配资源给其他程序,你再去delete,就会出错
深拷贝:其实深拷贝,就是自己写operotor=赋值函数
2.模板template
模板,代码复用技术
2.1函数模板
采用函数模板,根据传参类型,自动生成对应的模板
template < typename T >//函数模板,根据传参,解决多个版本问题
//等价于 template < class T>
//函数模板可以设置默认参数
T add(T a,T b)
{ return a+b; }
模板特例化: 指定参数类型。
T add(T a,T b)//除了char以外的版本做加法
{ return a+b; }
char add(char a,char b)//char类的版本做减法,特例化的优先级更高
{ return a-b; }
2.2类模板
所谓类模板,实际是建立一个通用类,其数据成员,成员函数的返回类型和形参类型不具体指定,用一个虚拟的类型来代表。使用类模板定义对象时,系统会根据实参的类型来取代类模板中虚拟类型从而实现了不同类的功能
//类模板-- 解决存储任意类型
1.把所有的数据的类型(int)换成T,有些用于表示数量的不用换
2.写上模板的声明(开头)
template < typename T>
3.定义对象时,在对象前加上 <数据类型>
4.如果把成员函数移到class外面(加上类名和作用域访问符)。需要在每个成员函数上方加上模板声明
5.在作用域访问符之前,类名之后,加上 < T>.
template < typename T>
void Stack < T>::insert()
{
}
Stack < int> a1;
2.3作业
1.实现字符串类
+- == +=
类内部的变量最好用this指向,以免再开一个空间
#include <iostream>
#include <string.h>
using namespace std;
class Mystring
{
public:
Mystring(const char *str="")//构造函数
{
cout <<"构造函数" <<endl;
this->len=strlen(str);
this->buf= new char [len+1];//加上'\0'
this->size=len;
strcpy(buf,str);
if(this->len!=0)
{
buf[this->len]='\0';
}
//cout << len << " " <<size << endl;
}
~Mystring() //析构函数
{
cout << "析构函数"<<endl;
delete [] buf;
}
void print()
{
cout << this->buf << endl;
}
void reserver(int n)//原本空间不够时,重新开辟空间
{
cout <<"原字符串内存不够" <<endl;
//cout << "size " << size <<" n " << n<<endl;
if(n>size)
{
char *tmp= new char[n+1];//开辟新的空间
if(n!=0)
{
strcpy(tmp,buf);//复制源字符串中的内容
}
delete []buf; //删除源字符串的空间
buf=tmp; //把新字符串赋值给源字符串
size=n; //最大长度更改
}
cout << "开辟完成" << endl;
}
Mystring operator=(Mystring &obj)//两个类的赋值函数
{
cout <<"两个类的赋值" <<endl;
this->reserver(obj.len);//如果原本的空间不够,就重新开辟空间
int i;
for(i=0;i<obj.len;i++)
{
buf[i]=obj.buf[i];
}
buf[i]='\0';//最后一位得用'\0'标记结尾
return *this;
}
Mystring operator=(const char *str)//类和字符串的赋值函数
{
cout <<"类与字符串的赋值" <<endl;
this->reserver(strlen(str));//如果原本的空间不够,就重新开辟空间
int i;
for(i=0;i<strlen(str);i++)
{
buf[i]=str[i];
}
buf[i]='\0';//最后一位得用'\0'标记结尾
return *this;
}
Mystring operator=(const char ch)//类和字符的赋值函数
{
cout <<"类与字符的赋值" <<endl;
this->reserver(1);//如果原本的空间不够,就重新开辟空间
buf[len]=ch;
buf[len+1]='\0';//最后一位得用'\0'标记结尾
return *this;
}
Mystring(const Mystring &obj) //对象拷贝构造函数
{
cout <<"拷贝构造函数" <<endl;
// cout <<"obj.buf " << obj.buf <<endl;
// cout << "obj.len" << obj.len<<endl;
// this->reserver(obj.len);//如果原本的空间不够,就重新开辟空间
//char *buf= new char[strlen(obj.buf)+1];//开辟新的空间
buf= new char[strlen(obj.buf)+1];//开辟新的空间
strcpy(buf,obj.buf);
//cout << "buf :" <<buf <<endl;
len = obj.len ;
size = obj.size;
// cout << "len:" << len<< endl;
// cout <<"size: " <<size <<endl;
}
/*
Mystring(const char *str) //字符串拷贝构造函数
{
cout <<"字符串拷贝构造函数" <<endl;
len = strlen(str);
// 开辟比源串长 1 的空间,'\0'
buf = new char[len+1];
//赋值
strcpy(buf,str);
size = len;
}
*/
Mystring operator+=(Mystring &obj)//两个类的赋值函数
{
cout << "两个类的赋值函数" << endl;
this->reserver(obj.len+len);//如果原本的空间不够,就重新开辟空间
int i,j=0;
for(i=len;i<obj.len+len;i++)//i从第一个字符串的末未开始 ,执行第二个字符串的有效长度次
{
buf[i]=obj.buf[j++];
}
this->buf[i]='\0';
return *this;
}
Mystring operator+=(const char *str)//类和字符串常量的赋值函数
{
cout << "类和字符串常量的赋值函数" << endl;
this->reserver(strlen(str)+len);//如果原本的空间不够,就重新开辟空间
int i,j=0;
for(i=len;i<strlen(str)+len;i++)//i从第一个字符串的末未开始 ,执行第二个字符串的有效长度次
{
buf[i]=str[j++];
}
this->buf[i]='\0';
return *this;
}
Mystring operator+=(const char ch)//类和字符的赋值函数
{
cout << "类和字符的赋值函数" << endl;
this->reserver(len+1);//如果原本的空间不够,就重新开辟空间
buf[len]=ch;
buf[len+1]='\0';
return *this;
}
int operator==(Mystring &obj)//比较函数
{
if(len!=obj.len)
{
return 0;
}
int i;
for(i=0;i<len;i++)
{
if(buf[i]!=obj.buf[i])
{
return 0;
}
}
return 1;
}
int operator==(const char *str)//比较函数
{
if(len!=strlen(str))
{
return 0;
}
int i;
for(i=0;i<len;i++)
{
if(buf[i]!=str[i])
{
return 0;
}
}
return 1;
}
int operator==(const char ch)//比较函数
{
if(len!=1)
{
return 0;
}
if(buf[0]!=ch)
{
return 0;
}
return 1;
}
private:
char *buf;//开辟空间的首地址
int len; //字符串的实际长度
int size; //总的开辟长度
};
int main()
{
Mystring s1 = "hello";//字符串拷贝构造
cout << "s1= " << endl;
s1.print();
Mystring s2("world");//构造函数
cout << "s2= " << endl;
s2.print();
Mystring s3=s1;
cout << "s3= " << endl;
s3.print();
Mystring s4;
s4="kunming";
cout << "s4= " << endl;
s4.print();
if(s1==s3)
{
cout <<"相等" << endl;
}
else
{
cout <<"不相等" << endl;
}
if(s1=="hello")
{
cout <<"相等" << endl;
}
else
{
cout <<"不相等" << endl;
}
s1+=s2;
cout << "s1+s2 : " << endl;
s1.print();
s2+=" nihao";
s2.print();
return 0;
}
2.设计数组类,可以存储任意类型(类模板),支持cout输出,下标运算[] (Array obj;obj[2];)
友元也可以写在类里
构造函数的形参都要加上const
友元函数的<< 重载,运用到类模板,友元函数不在类中,需要在类中为友元函数重新定义一个模板类template < typename C>,其他的模板为template < typename T>,定义时两个末班都可以
#include <iostream>
//**2. 设计数组类,可以存储任意类型。支持cout输出,下标运算[] ( Array obj; obj[2]; )**
using namespace std;
template <typename T>
class Array
{
public:
Array(int n=5)
{
this->data= new T[n];
this->len=0;
this->size=n;
}
~Array()
{
delete []data;
this->len=0;
this->size=0;
}
void set_array(T x)
{
this->data[this->len++]=x;
}
void print_array()
{
int i;
for(i=0;i<len;i++)
{
cout << data[i] << " ";
}
cout << endl;
}
T operator[](int x)
{
return this->data[x];
}
//template <typename C> //友元函数在类外面时,需要为友元函数定义一个模板
//friend ostream & operator<<(ostream &out , Array<C> &obj)
friend ostream & operator<<(ostream &out , Array<T> &obj)
{
int i;
for(i=0;i<obj.len;i++)
{
out<< obj.data[i] ;
}
out << endl;
return out;
}
private:
T *data; //数组首地址
int len; //有效长度
int size; //总长度
};
// template <typename T/C>
// ostream & operator<<(ostream &out , Array <T/C> &obj) //普通函数不用写域访问符
// {
// int i;
// for(i=0;i<obj.len;i++)
// {
// out<< obj.data[i] ;
// }
// out << endl;
// return out;
// }
int main()
{
Array <int> a(5);
a.set_array(0);
a.set_array(1);
a.set_array(2);
a.set_array(3);
a.set_array(4);
//a.print_array();
cout << "a:整形 " <<endl;
cout << a <<endl; //重载<<
Array <char> a1(5);
a1.set_array('a');
a1.set_array('b');
a1.set_array('c');
a1.set_array('d');
a1.set_array('e');
//a1.print_array();
cout << "a1字符 " <<endl;
cout << a1[0] ;
cout << a1[1] ;
cout << a1[2] ;
cout << a1[3] ;
cout << a1[4] << endl; //数组下标
cout << endl;
Array <double> a2(5);
a2.set_array(0.12);
a2.set_array(1.12);
a2.set_array(2.12);
a2.set_array(3.12);
a2.set_array(4.12);
cout <<"a2 double" << endl;
a2.print_array();
cout << endl;
Array <string> a3(5);
a3.set_array("hello");
a3.set_array("world");
a3.set_array("so");
a3.set_array("lovely");
a3.set_array("you");
cout <<"a3 string" << endl;
a3.print_array();
cout << endl;
return 0;
}