VC C++程序设计学习总结与心得Word格式.docx
- 文档编号:19132817
- 上传时间:2023-01-04
- 格式:DOCX
- 页数:27
- 大小:81.93KB
VC C++程序设计学习总结与心得Word格式.docx
《VC C++程序设计学习总结与心得Word格式.docx》由会员分享,可在线阅读,更多相关《VC C++程序设计学习总结与心得Word格式.docx(27页珍藏版)》请在冰豆网上搜索。
——错误4*/
//不能通过指针修改指向的值
/*a_ptr=&
c;
——错误5*/
//a_ptr=&
错
//定义的常量指针,不能修改指向的地址
第一个const限定不能由该指针去改变被指对象的值,第二个const限定不能改变指针所指的对象
1.6修饰引用,如:
constint&
bb=b;
b=2;
//ok
//bb=2;
//error
引用的对象默认就不可以修改,再加上第一个const之后,也不能通过本引用名对其进行修改
1.7修饰类的数据成员
必须在初始化列表中进行初始化或者在类外进行初始化,不能在构造函数的大括号里面进行初始化
2、面向对象与面向过程
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
面向对象程序的基本特点:
抽象、封装、继承、多态。
面向对象的优点:
1结构清晰。
使人们的编程与实际的世界更加接近,所有的对象被赋予属性和方法,结果编程就更加富有人性化。
2封装性。
减小外部对内部的影响。
封装将对象有关的数据和行为封装成整体来处理,使得对象以外的部分不能随意存取对象的内部属性,从而有效地避免了外部错误对它的影响,大大减小了查错和排错的难度。
3容易扩展,代码重用率高。
容易扩展,在大框架不变的情况下很容易就开发出适合自己的功能,实现简单,可有效地减少程序的维护工作量,软件开发效率高。
面向过程的优点:
易于经常以只读的方式读取数据
3、构造函数和析构函数
构造函数作用:
在对象被创建时利用特定的值创建对象,将对象初始化一个固定的状态。
构造函数在创建时被自动调用。
编译器会自动生成无参数的构造函数,但是一旦你定义了自己的构造函数,系统默认构造函数将失效
拷贝构造函数作用:
使用已经存在的一个对象,去初始化一个同类的新对象
拷贝构造函数调用的三种情况:
1、类对象作为函数的返回值,执行完成返回时
2、类对象作为函数的形参与实参结合时
3、用类对象对另一个类对象进行赋值或初始化
析构函数作用:
完成对象被删除前的清理工作,释放对象所占有的内存。
析构函数在对象生存期即将结束时被自动调用,且不接受任何参数
构造函数调用顺序:
按声明的继承顺序,然后时定义类成员实例的顺序。
类内嵌则先调用内嵌对象的构造函数,然后调用本类
析构函数调用顺序与其相反
深拷贝和浅拷贝:
若自动调用默认的拷贝构造函数是浅拷贝,与被拷贝对象共用内存
若想有独立内存,必须进行深拷贝,相当于利用被拷贝对象的成员变量值重新进行构造,如:
CmcArrayOfPoint2:
:
CmcArrayOfPoint2(constCmcArrayOfPoint2&
array)
{
cout<
"
CmcArrayOfPoint2的拷贝构造函数被调用!
"
<
this->
m_n_num=array.m_n_num;
point_ptr=newCmcPoint[array.m_n_num];
for(inti=0;
i<
=this->
m_n_num-1;
i++)
this->
get_point(i).set_xy(array.get_point(i).get_x(),array.get_point(i).get_y());
}
前向引用声明总结:
1、不能调用没有实现的类
2、可以以形参形式在内联函数中使用,但不能用于类内实现
3、不能在实现前涉及该类的任何细节
4、指针与引用
指针本身为unsignedlongint类型
const在前为指向常量的指针,const在*后为指针类型的常量
不能声明void的类型的变量,但是可以声明使用void类型的指针,赋值时其他类型的指针可以赋值给void*,但是void指针对其他指针赋值需要进行强制类型转换。
函数指针:
数据类型(*函数指针名)(形参表)
【函数名本身就是函数指针】,如:
voidf1(inta);
voidf2(inta,intb);
intf3(doublea);
voidf4(doublea);
void(*func_ptr)(double);
doubled=1.1;
func_ptr=f4;
(*func_ptr)(d);
//func_ptr=f3;
//错误!
!
//func_ptr=f2;
//func_ptr=f1;
必须使用时符合函数指针声明时的返回值类型和参数类型。
指向类成员函数的函数指针需要被声明为:
数据类型(类名:
:
*函数指针名)(形参表)如:
int(A:
*fp)(void)=&
A:
get_a;
int(*f)(void);
//f=A:
错误!
C++标准规定,不能将非静态成员函数名直接赋值给成员函数指针,必须进行取地址运算。
非静态成员函数调用时也必须基于类对象,利用.*运算符进行调用,如:
(Ca.*fp)()<
ends;
对象指针是指指向对象的指针,this指针是隐含于每一个类的成员函数中的特殊指针(包括构造、析构函数),用于指向正在被操作的对象。
指向非静态数据成员的指针需要被声明为类型(类名:
*指针名)
指向静态数据成员的指针需要被声明为类型*指针名
同理,非静态的数据成员也需要建立在类对象的基础上进行访问
5、静态数据成员和友元
静态数据成员具有静态生存期,可以用类名:
标识符进行访问,由该类的所有对象共同维护和使用
必须在文件作用域对静态数据成员进行初始化,如:
intCmcPoint:
c_n_count=0;
//必须进行初始化定义性说明
友元函数是在类中定义的非成员函数(所以也不能引用this指针),如:
frienddoubleget_length(constCmcPoint&
p1,constCmcPoint&
p2);
//返回两个点之间的距离(友元函数)
//不能用const修饰!
?
尽量传引用?
友元函数说明如下:
1)必须在类的说明中说明友元函数,说明时以关键字friend开头,后跟友元函数**的函数原型,友元函数的说明可以出现在类的任何地方,包括在private和public部分;
2)注意友元函数不是类的成员函数,所以友元函数的实现和普通函数一样,在实现时不用"
指示属于哪个类,只有成员函数才使用"
作用域符号;
3)友元函数不能直接访问类的成员,只能访问对象成员,
4)友元函数可以访问对象的私有成员,但普通函数不行;
5)调用友元函数时,在实际参数中需要指出要访问的对象,
6)类与类之间的友元关系不能继承。
类的友元关系说明如下:
(1)友元关系不可继承
(2)友元关系是单向的
(3)友元关系是不可传递的
6、函数的重载和默认形参
定义:
两个以上的函数,具有相同函数名和类似的功能,但是形参的个数和类型不同,编译器在调用时对其进行自动匹配。
(C++语法,C语言不支持重载)
能作为重载的区分:
1、函数的形参个数
2、函数的形参类型
3、常函数的const标识符
待默认形参的函数:
声明时时只能从右向左缺省,而且必须给出缺省值
定义时(实现时)不必给出缺省值
7、运算符重载
运算符重载是指对已有的运算符赋予多重含义,使得同一个运算符作用与不同类型的数据时,导致不同的行为。
可以以友元函数的形式或者类成员函数的形式。
不能重载的运算符:
类属运算符(.)成员指针运算符(.*)作用域运算符(:
)sizeof运算符和
三目运算符(?
)
关于运算符(++,--)前置后置问题,如
Clock&
operator++();
//前置单目运算符重载
operator++(int);
//后置单目运算符重载
调用时像正常形式调用就行
关于CString的运算符重载(声明部分):
classCMyString
public:
CMyString(inti_n_length=INIT_SIZE);
//默认构造函数
CMyString(constchar*i_c_str);
//含有一个参数的构造函数
CMyString(constCMyString&
i_s_str);
//拷贝构造函数
~CMyString();
//析构函数
CMyStringoperator=(constCMyStringi_s_str);
//重载赋值运算符
CMyStringoperator+(constCMyStringi_s_str);
//重载加法运算符
CMyStringoperator+=(constCMyStringi_s_str);
//重载加等于运算符
friendbooloperator==(constCMyString&
i_s_str1,constCMyString&
i_s_str2);
//重载判断是否相等运算符
voidshow()const;
//打印字符串
private:
char*m_c_path;
//初始地址
intm_n_length;
//当前字符串长度
intm_n_max_size;
//最大的储存空间
};
实现部分(基于<
string.h>
):
CMyString:
CMyString(inti_n_length/*INIT_SIZE*/)//默认构造函数
m_c_path=(char*)malloc(sizeof(char)*i_n_length);
m_c_path[0]='
\0'
m_n_length=0;
m_n_max_size=i_n_length;
CMyString(constchar*i_c_str)//含有一个参数的构造函数
m_n_length=strlen(i_c_str);
m_n_max_size=strlen(i_c_str);
m_c_path=(char*)malloc(sizeof(char)*this->
m_n_length);
strcpy(this->
m_c_path,i_c_str);
CMyString(constCMyString&
i_s_str)//拷贝构造函数
m_c_path=(char*)malloc(sizeof(char)*i_s_str.m_n_max_size);
=i_s_str.m_n_length/*!
!
不是-1!
*/;
m_c_path[i]=i_s_str.m_c_path[i];
m_n_length=i_s_str.m_n_length;
m_n_max_size=i_s_str.m_n_max_size;
~CMyString()
m_c_path=NULL;
m_n_length=0;
m_n_max_size=0;
CMyStringCMyString:
operator=(constCMyStringi_s_str)
free(this->
m_c_path);
returni_s_str;
operator+(constCMyStringi_s_str)
CMyStringc_str(this->
m_n_max_size+i_s_str.m_n_max_size);
c_str.m_n_max_size=this->
m_n_max_size+i_s_str.m_n_max_size;
c_str.m_n_length=this->
m_n_length+i_s_str.m_n_length;
c_str.m_c_path=(char*)malloc(sizeof(char)*c_str.m_n_max_size);
strcpy(c_str.m_c_path,this->
strcat(c_str.m_c_path,i_s_str.m_c_path);
c_str.m_c_path[c_str.m_n_length]='
returnc_str;
operator+=(constCMyStringi_s_str)
m_n_max_size+=i_s_str.m_n_max_size;
m_c_path=(char*)realloc(this->
m_c_path,
sizeof(char)*this->
m_n_max_size);
m_c_path[this->
m_n_length]='
m_n_length+=i_s_str.m_n_length;
strcat(this->
m_c_path,i_s_str.m_c_path);
//需要足够的空间
return(*this);
voidCMyString:
show()const//打印字符串
m_c_path<
booloperator==(constCMyString&
i_s_str2)
//重载判断是否相等运算符
if(i_s_str1.m_c_path==NULL||i_s_str2.m_c_path==NULL)
{
if(i_s_str1.m_c_path!
=i_s_str2.m_c_path)//不同时为空
returnfalse;
}
if(i_s_str1.m_n_length!
=i_s_str2.m_n_length)
returnfalse;
if(strcmp(i_s_str1.m_c_path,i_s_str2.m_c_path)!
=0)
returntrue;
微软的实现方式:
char*strcpy(char*dst,constchar*src)
char*cp=dst;
while(*cp++=*src++)
;
//Copysrcoverdst
return(dst);
}//Microsoft的实现方式
intstrcmp(constchar*src,constchar*dst)
intret=0;
while(!
(ret=*(unsignedchar*)src-*(unsignedchar*)dst)&
&
*dst)
++src,++dst;
if(ret<
0)
ret=-1;
elseif(ret>
ret=1;
return(ret);
char*strcat(char*dst,constchar*src)
while(*cp)
cp++;
//findendofdst
while(*cp++=*src++);
//Copysrctoendofdst
//returndst
8、类的继承和派生
构造函数和析构函数不会被继承
私有继承和protected类型继承会把父类的public成员变成对应的类型,有多个基类(多继承),一个(单继承)
从两个不同基类继承来的同名成员,如果不在本类进行覆盖,直接调用,将会导致二义性,编译无法通过,需要利用作用域运算符,会有两份内存分配。
默认为私有继承。
公有继承:
public和protected类属性不变,private类被隐藏,不能直接进行调用。
保护继承:
public和protected类以protected类的属性出现,私有成员不能直接访问。
私有继承:
public和protected类以private类的属性出现,私有成员不能直接访问。
构造派生类对象时,就要对基类数据成员、新增数据成员和成员对象的数据成员进行初始化。
9、虚基类、虚函数、纯虚函数
将继承中的共同基类设置成虚基类,这时从不同路径继承来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射,不会出现二义性。
如:
classCmcBird:
virtualpublicCmcAnimal
//将CmcAnimal视为虚基类
classCmcHorse:
classCmcFlyHorse:
publicCmcBird,publicCmcHorse
如果使用非默认形式的构造函数,在整个继承关系中,直接或者间接继承虚基类的所有派生类,都必须在构造函数初始化列表中给出初始化。
虚函数是动态绑定的基础,且必须是非静态的成员函数。
(如果认为该类会被继承,最好声明其方法为虚函数,但是需要生成虚函数列表,会一定程度上影响性能)
通俗来看,如果一个基类成员函数不是虚函数的话,其派生类将该成员函数覆盖后,利用该基类的指针(或引用),即使指向(引用)的是一个派生类的实例,也只能对基类的函数进行调用。
CmcAnimal*animal=newCmcAnimal;
CmcAnimal*bird=newCmcBird;
CmcAnimal*horse=newCmcHorse;
animal->
move();
horse->
bird->
其中CmcBird、CmcHorse类分别继承了CmcAnimal类,并覆盖了其move()方法,如果在CmcAnimal类中,move()不是虚函数,运行结果为:
如果用virtual标识符对CmcAnimal的move函数进行声明(定义时不必加),即:
virtualvoidmove();
//动物的移动函数
运行结果为:
即基类指针分别正确调用了子类的move()方法
注意:
不能声明类的虚构造函数,析构函数可以,用来指向性清理
抽象类是为了抽象和设计为目的建立的,不能实例化其本身,只能实例其非抽象派生类。
抽象类带有纯虚函数。
纯虚函数是特殊的虚函数(比虚函数还虚……),声明举例如下:
virtualvoidmove()=0;
//动物的移动函数,纯虚函数,必须进行覆盖
声明了纯虚函数后,基类中就不必给出其实现部分【试了一下,给出实现部分也能编译通过,但是没有任何实际意义,因为子类肯定会覆盖它】,函数体由派生类给出。
因为你无法使用基类指针指向基类,如:
//CmcAnimal*animal=newCmcAnimal;
//error因为包含纯虚函数,因此CmcAnimal是一个抽象类
所以无法通过指针调用纯虚函数在基类中的实现,因此完全没有意义。
但是你可以声明抽象基类的指针指向非抽象子类,这是正确的,而且能调用正确的方法:
但是但是,如果通过这种方法:
CmcHorsehorse2;
horse2.CmcAnimal:
//ok!
可以利用作用域进行直接调用,虽然是纯虚函数,但是可以被调用!
//不过既然作为纯虚函数,有定义应该是件不适合的事情
强行通过子类实例的作用域运算符对其调用,可以使用该纯虚函数!
——非常有趣
这样做未免有点过于较劲了,而忽略了纯虚函数的抽象类的目的,只有你绝对肯定不需要使用该类的对象和其成员方法时,你才会将其声明为抽象类和纯虚函数。
最后,如果一个类由抽象类派生,但没有
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VC C+程序设计学习总结与心得 C+ 程序设计 学习 总结 心得