C++程序设计-大模型思维与实践课件 第13章 类与对象(二)进阶内容_第1页
C++程序设计-大模型思维与实践课件 第13章 类与对象(二)进阶内容_第2页
C++程序设计-大模型思维与实践课件 第13章 类与对象(二)进阶内容_第3页
C++程序设计-大模型思维与实践课件 第13章 类与对象(二)进阶内容_第4页
C++程序设计-大模型思维与实践课件 第13章 类与对象(二)进阶内容_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第十三章类与对象(二)C++程序设计——大模型思维与实践内容导航引言运算符重载静态成员类模板友元应用实例常成员与常对象大模型探究拷贝构造函数类与对象(二)3class

MyString{private:char*Str;//字符串指针int

len;//字符串长度public:void

ShowStr();//显示字符串内容和长度MyString(const

char*

p=NULL);//构造函数MyString(const

MyString&

s);//拷贝构造函数MyString&

operator=(const

MyString&

s);//赋值运算符重载~MyString();//析构函数char&

operator[](int

n);//重载运算符[],处理String对象const

char&

operator[](int

n)const;//重载运算符[],处理constString对象friend

ostream&

operator<<(ostream&

os,const

MyString&

s);friend

istream&

operator>>(istream&

is,MyString&

s);friend

bool

operator==(const

MyString&

s1,const

MyString&

s2);friend

MyString

operator+(const

MyString&

s1,const

MyString&

s2);};例:模仿C++的string类,定义MyString类,以更深入理解string类的实现机制。运算符重载:MyString类

4//显示字符串内容和长度void

MyString::ShowStr(){ cout<<"string:"<<Str<<",length:"<<len<<endl;}运算符重载:MyString类

//构造函数MyString::MyString(const

char*p){if(p){len=strlen(p);//获取字符串长度Str=new

char[len+1];//分配内存strcpy(Str,p);//复制字符串内容}else{len=0;Str=NULL;}}//拷贝构造函数MyString::MyString(constMyString&s){if(s.Str){len=s.len;//复制字符串长度Str=new

char[len+1];//分配内存strcpy(Str,s.Str);//复制字符串内容}else{len=0;Str=NULL;}}5//赋值运算符重载MyString&

MyString::operator=(const

MyString&

s){if(this==&s){ return*this;//处理自赋值}delete[]Str;//释放旧内存if(s.Str){len=s.len;//复制字符串长度Str=new

char[len+1];//分配内存strcpy(Str,s.Str);//复制字符串内容}else{len=0;Str=NULL;}return*this;//返回当前对象的引用}运算符重载:MyString类

//析构函数MyString::~MyString(){

if(Str!=NULL)delete[]Str;//释放内存}//重载运算符[],处理String对象char&

MyString::operator[](int

n){

return

Str[n];}//重载运算符[],处理constString对象const

char&

MyString::operator[](int

n)const{

return

Str[n];}6//重载输出运算符ostream&

operator<<(ostream&

os,const

MyString&

s){os<<s.Str;returnos;}运算符重载:MyString类

//重载输入运算符istream&

operator>>(istream&

is,MyString&

s){char

temp[100];is>>temp;s=MyString(temp);return

is;}//重载相等运算符bool

operator==(const

MyString&

s1,const

MyString&

s2){

return

strcmp(s1.Str,s2.Str)==0;}//重载加法运算符MyString

operator+(const

MyString&

s1,const

MyString&

s2){char*s=new

char[s1.len+s2.len+1];strcpy(s,s1.Str);strcat(s,s2.Str);MyStringresult(s);delete[]

s;//释放临时内存return

result;}7运算符重载:MyString类

int

main(void){MyStringS1("0123456789abcdef");S1.ShowStr();S1[10]='A';cout<<"afterS1[10]=A"<<endl;S1.ShowStr();constMyStringS2(S1);cout<<"S2[3]="<<S2[3]<<endl;cout<<"S1==S2is"<<(S1==S2)<<endl;cout<<"PleaseinputS1:";cin>>S1;MyStringS3;S3=S1+S2;cout<<S3;return

0;}string:0123456789abcdef,length:16afterS1[10]=Astring:0123456789Abcdef,length:16S2[3]=3S1==S2is1PleaseinputS1:abcdabcd0123456789Abcdef

8运算符重载:MyString类

1.内存管理MyString类使用new和delete[]进行动态内存分配和释放。在创建对象时分配内存,销毁对象时释放内存,因此要正确定义构造函数和析构函数。由于该类涉及到了深拷贝,需要定义拷贝构造函数和重载赋值运算符,确保每个对象都有自己独立的内存空间。2.常量成员函数重载的operator[]有两个版本,一个用于非const对象,一个用于const对象。需要理解const成员函数的作用和使用场景。3.友元函数友元函数可以访问类的私有成员,因此重载的运算符都定义为了友元函数。4.输入输出运算符重载重载<<和>>运算符,使得MyString对象可以直接用于标准输入输出流。5.相等运算符重载重载==运算符,使得可以比较两个MyString对象是否相等。6.加法运算符重载重载+运算符,使得可以连接两个MyString对象。

9运算符重载:MyString类

7.赋值运算符重载作用是将一个MyString对象的值赋给另一个MyString对象。函数体的代码解释如下:(1)自赋值检查 if(this==&s){

return*this;//处理自赋值

}(2)释放旧内存:释放当前对象中原有的字符串内存,防止内存泄漏。(3)复制新值:将源对象的字符串内容复制到当前对象中。步骤如下:• 首先检查源对象是否有字符串:如果s.Str不为空,则进行复制。• 获取字符串长度:将源对象的字符串长度赋值给当前对象的len。• 分配内存:为当前对象的字符串分配足够的内存(包括终止符\0)。• 复制字符串内容:使用strcpy函数将源对象的字符串内容复制到当前对象的字符串指针Str。• 处理空字符串:如果源对象的字符串为空,则将当前对象的len设为0,Str设为NULL。(4)返回当前对象的引用,以支持链式赋值。 return*this;//返回当前对象的引用内容导航引言运算符重载静态成员类模板友元应用实例常成员与常对象大模型探究拷贝构造函数类与对象(二)11template<class

T1,class

T2,int

N>class

Student{private:T1

studentID;T2

score[N];public:Student(T1

id):studentID(id){for(int

i=0;i<N;i++)score[i]=0;}void

display(){cout<<"ID:"<<studentID<<endl<<"Score:"<<endl;for(int

i=0;i<N;i++)cout<<score[i]<<"";cout<<endl;}};在类模板中声明非类型参数示例:非类型参数

int

main(){Student<string,int,3>s1("B305");s1.display();Student<int,double,5>s2(1001);s2.display();return

0;}

ID:B305Score:000非类型参数stringstudentID;intscore[3];

intstudentID;doublescore[5];

ID:1001Score:0000012template<class

T1,class

T2=int,int

N=10>class

Student{private:T1

studentID;T2

score[N];public:Student(T1

id):studentID(id){for(int

i=0;i<N;i++)score[i]=0;}void

display();类内声明};C++11及之后的版本允许为非类型参数指定默认值。

非类型参数

int

main(){Student<string>s1("B305");s1.display();Student<int,double>s2(1001);s2.display();Student<int,double,5>s3(1002);s3.display();return

0;}T1=string;T2=intN=10

T1=int;T2=doubleN=10

T1=intT2=doubleN=5//类外实现display()函数template<class

T1,class

T2,int

N>void

Student<T1,T2,N>::display(){cout<<"ID:"<<studentID<<endl<<"Score:"<<endl;for(int

i=0;i<N;i++)cout<<score[i]<<"";cout<<endl;}13非类型参数

int

main(){Student<string>s1("B305");s1.display();Student<int,double>s2(1001);s2.display();Student<int,double,5>s3(1002);s3.display();return

0;}ID:B305Score:0000000000ID:1002Score:00000ID:1001Score:000000000014使用非类型参数的注意事项:(1)非类型参数的类型非类型参数的类型必须是整型、浮点型、枚举型或指针类型等常量表达式。不能是类类型或string、vector等。(2)默认值的类型匹配非类型参数的默认值必须是编译时常量,并且其类型必须与参数声明的类型匹配。如果类型不匹配,编译器将报错。(3)默认参数的连续性如果为类模板的某个参数指定了默认值,那么从这个参数开始,之后的所有参数(如果有的话)都必须指定默认值。然而,这个规则只适用于类型参数和非类型参数的混合情况。对于纯类型参数列表,可以跳过某些参数而只为后面的参数指定默认值,但这在实践中并不常见。非类型参数

public://构造函数MyVector(){size=0;capacity=10;data=new

T[capacity];}~MyVector(){delete[]

data;}

//析构函数bool

isEmpty()const{return

size==0;}//判断是否为空size_t

length()const{return

size;}

//返回长度void

push_back(const

T&

value);

//插入元素void

remove(size_t

index);

//删除元素T&

operator[](size_t

index);

//重载[]下标运算符const

T&

operator[](size_t

index)const;};};15#include

<iostream>#include

<stdexcept>using

namespace

std;template<typename

T>class

MyVector{private:T*data;//动态数组指针size_t

size;//当前元素数量size_t

capacity;//数组容量//扩展容量void

expandCapacity();例:模仿C++的vector类,定义MyVector类,以更深入理解vector类的实现机制。MyVector类

模板类size_t一种无符号整数类型.在32位系统,为32位;在64位系统,为64位//插入元素到末尾template<typename

T>void

MyVector<T>::push_back(const

T&

value){if(size==capacity){//如果数组已满,则扩展容量expandCapacity();}data[size++]=value;}16//扩展容量template<typename

T>void

MyVector<T>::expandCapacity(){capacity=capacity*2;T*newData=new

T[capacity];for(size_ti=0;i<size;++i){ newData[i]=data[i];}delete[]data;data=newData;}MyVector类

数组容量扩展为原来的两倍,并将旧数据复制到新数组中。

expandCapacity方法定义为私有两原因:(1)防止误用:若公有,用户调用不当导致数据不一致(2)自动管理:改方法由类的内部逻辑自动管理,提高代码的健壮性。//重载[]下标运算符template<typename

T>T&

MyVector<T>::operator[](size_t

index){if(index>=size){ throw

out_of_range("Indexoutofrange");}return

data[index];}

template<typename

T>const

T&

MyVector<T>::operator[](size_t

index)const{if(index>=size){ throw

out_of_range("Indexoutofrange");}return

data[index];}17//删除下标index处的元素template<typename

T>void

MyVector<T>::remove(size_t

index){if(index>=size){ throw

out_of_range("Indexoutofrange");}for(size_ti=index;i<size-1;++i){ data[i]=data[i+1];}--size;}MyVector类

18int

main(){MyVector<int>vec;vec.push_back(1);vec.push_back(2);vec.push_back(3);for(size_t

i=0;i<vec.length();++i){ cout<<"元素"

<<i<<":"<<vec[i]<<endl;}vec.remove(1);cout<<"删除元素后:"

<<endl;for(size_t

i=0;i<vec.length();++i){ cout<<"元素"

<<i<<":"<<vec[i]<<endl;}return

0;}MyVector类

元素0:1元素1:2元素2:3删除元素后:元素0:1元素1:3内容导航引言运算符重载静态成员类模板友元应用实例常成员与常对象大模型探究拷贝构造函数类与对象(二)2013.9大模型探究【提问】:学习C++的运算符重载时,教材说:对于形如@obj的一元运算符表达式,如果@被重载,编译器会将其转换为obj.operator@()或operator@(obj)。但是一元运算符++有前置和后置的区分,在重载时怎么区分呢?请举例说明如何重载这两个运算符。探究1【回复】:在C++中,重载一元运算符++时,前置和后置运算符的重载方式有所不同。前置运算符++和后置运算符++的重载需要通过不同的函数签名来区分。前置运算符++的重载函数没有参数,通常返回对自身的引用。后置运算符++的重载函数有一个int类型的参数,这个参数在调用时不使用,但用于区分前置和后置运算符。后置运算符通常返回对象的副本。以下是一个示例,展示如何重载前置和后置运算符++:21#include

<iostream>using

namespace

std;class

Counter{private:int

value;public:Counter():value(0){}//前置++运算符重载Counter&

operator++(){++value;return*this;}//后置++运算符重载Counter

operator++(int){Counter

temp=*this;value++;return

temp;}13.9大模型探究1.前置运算符++重载:

-这个函数没有参数。-它增加对象的value,然后返回对自身的引用。2.后置运算符++重载-这个函数有一个int类型的参数,但在函数体内不使用。-它首先保存对象的当前状态,然后增加value,最后返回保存的副本。

2213.9大模型探究int

getValue()const{ return

value;}};int

main(){Counterc;cout<<"初始值:"

<<c.getValue()<<endl;++c;//调用前置++cout<<"前置++后:"

<<c.getValue()<<endl;c++;//调用后置++cout<<"后置++后:"

<<c.getValue()<<endl;return

0;}3.使用示例-++c调用前置运算符,直接增加value并返回自身。c++调用后置运算符,返回增加前的副本。通过这种方式,可以清晰地区分和重载前置和后置的++运算符。2313.9大模型探究【提问】:能否通过一个实例,演示一下构造函数、拷贝构造函数、析构函数三者的调用时机。探究2【回复】:好的,通过一个对象以值传递的方式传入函数体的实例来演示一下三者的调用时机。24#include

<iostream>using

namespace

std;class

Location{public:Location(int

xx=0,int

yy=0){X=xx;Y=yy;cout

<<

"ConstructorObject.\n";}Location(const

Location

&p)//复制构造函数{X=p.X;Y=p.Y;cout

<<

"Copy_constructorcalled."

<<

endl;}13.9大模型探究构造函数Location(intxx=0,intyy=0):这是

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论