C++学习笔记.docx
- 文档编号:14456748
- 上传时间:2023-06-23
- 格式:DOCX
- 页数:38
- 大小:303.93KB
C++学习笔记.docx
《C++学习笔记.docx》由会员分享,可在线阅读,更多相关《C++学习笔记.docx(38页珍藏版)》请在冰点文库上搜索。
C++学习笔记
C++学习笔记
1类
1.1类和对象
将数据及对数据的操作方法封装在一起,作为一个相互依存、不可分离的整体,这就是对象。
对同类型对象抽象出其共性,形成类。
类是对象的抽象,而对象是类的具体实例(instance)。
类是抽象的,不占用内存,而对象是具体的,占用存储空间。
对象与对象之间通过消息进行通讯。
1.2对象、方法、消息
类的成员函数在面向对象程序理论中被称为“方法”(method),“方法”是指对数据的操作。
只有被声明为公用的方法才能被外界对象所激活。
外界是通过发“消息”来激活有关方法的。
所谓“消息”,其实就是一个命令。
classSTUDENT
{
public:
voiddisplay();
...
}
STUDENTstud;
以上STUDENT是“类”,stud是“对象”,display()是“方法”。
stud.display();
就是向对象stud发出一个“消息”,通知它执行其中的display“方法”。
1.3构造函数
1.3.1默认构造函数
默认构造函数:
Complex();//默认构造函数没有参数
1.3.2用于初始化的构造函数
用于初始化的构造函数:
Complex(doubler,doublei);//形参列表中一般有两个以上参数
类的数据成员是不能在声明类时初始化的,必须通过构造函数初始化。
Complex:
:
Complex(doubler,doublei)
{
real=r;
imag=i;
......
}
C++还提供另一种初始化数据成员的方法--参数初始化表。
Complex:
:
Complex(doubler,doublei):
real(r),imag(i)
{
......
}
1.3.3复制构造函数
复制构造函数:
Box:
:
Box(constBox&b)
{
height=b.height;
width=b.width;
length=b.length;
}
复制对象box1的方法:
(Boxbox1;)
方法一:
Boxbox2(box1);
方法二:
Boxbox2=box1;
对象的复制与对象的赋值的区别:
复制构造函数:
使用一个现成的对象来“构造”另一个对象。
(一个对象已经存在,另一个之前不存在)
运算符重载:
两个对象都是已经“构造”过的,使用一个对象来重新设置另一个对象。
(两个对象都是已经存在的)。
对于编译器,如果不主动编写拷贝函数和赋值函数,它会以“位拷贝”的方式自动生成缺省的函数。
1.3.4转换构造函数
转换构造函数:
将其他类型转换为本类。
显式类型转换----类型名(数据),int(d);C语言中为:
(类型名)数据,(int)d。
建议使用C++的方法。
隐式类型转换----由C++编译系统自动完成。
如,inti=6;i=7.5+i;编译系统自动把6转换为double型。
对于用户自己声明的类型,编译系统并不知道怎样进行转换,需要定义专门的转换构造函数来处理。
转换构造函数只有一个形参,如:
Complex(doubler)
{
real=r;imag=0;
}
其作用是将double型的参数转变成Complex类的对象。
Complexc1(3,6),c;//假定已对运算符“+”进行了重载,能够进行两个Complex类对象相加。
c=c1+2.5 //编译出错,因为不能用运算符将一个Complex类对象和一个浮点数相加。
c=c1+Complex(2.5);//合法
1.3.5派生类的构造函数
派生类的构造函数:
派生类构造函数的任务应该包括3个部分,并按一下次序执行:
首先,对基类数据成员初始化;
然后,对子对象(即组合)数据成员初始化;
最后,对派生类数据成员初始化。
1.4析构函数
析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作。
它没有返回值,也没有参数,不能被重载,一个类只能有一个析构函数。
一般将析构函数声明为虚析构函数,即使基类并不需要析构函数,也显式地定义一个函数体为空的虚析构函数,以保证在撤销动态分配空间时能得到正确处理。
(原因详见多态的示例)。
如果派生类对象不是动态分配的,而是直接定义的,则不论析构函数是否是虚函数,在对象销毁时,都能正确地被依次调用(先调用派生类析构函数,再调用基类析构函数)。
1.5成员变量与成员函数
1.6成员变量及函数的访问权限
public、protect、private
1.7const
既要使数据能在一定范围内共享,又要保证它不被任意修改,这时可以使用const,即将有关数据定义为常量。
(与private比较)
1.7.1常对象
常对象:
Timeconstt1(12,34,46);或者写成
constTimet1(12,34,46);
注意:
如果一个对象被声明为常对象,则不能调用该对象的非const型的成员函数(除了由系统自动调用的隐式的构造函数和析构函数)。
常对象数据成员都是常数据成员,因此常对象的构造函数只能用参数初始化表对常数据成员进行初始化。
但常对象中的成员函数如果未加const声明,编译系统把该函数作为非cosnt成员函数处理。
1.7.2对象常成员
常数据成员
对象常成员----常数据成员
constinthour;//声明hour为常数据成员
注意:
不能在构造函数中对常数据成员赋初值。
下面的用法是非法的:
Time:
:
Time(inth)
{
hour=h;
}
在类外定义构造函数,应使用参数初始化表对常数据成员hour初始化:
Time:
:
Time(int):
hour(h)
{
}
常成员函数
对象常成员----常成员函数
voidTime:
:
fun()const;//fun是Time类中的常成员函数,可以引用,但不能修改本类中的数据成员。
注意:
const的位置在函数名和括号之后
在声明函数和定义函数时都要有const关键字,在调用时不必加const。
常成员函数不能调用另一个非const成员函数。
1.7.3指向常对象的指针
指向常对象的指针:
constTime*p;
p是指向Time类常对象的指针,其指向的类对象的值不能通过指针来改变。
1.7.4指向对象的常指针
指向对象的常指针:
Time*constp;
p是指向Time对象的常指针,p的值(即p的指向)不能改变。
1.7.5对象的常引用
对象的常引用:
constTime&t
如果不希望在函数中修改实参t的值,可以把参数定义为常引用,
voidfun(constTime&t);//在函数fun中不能改变形参t的值,也就是不能改变其对应实参的值。
C++面向对象程序设计中,经常用常指针和常引用作函数参数,这样既能保证数据安全,又能在调用函数时不必建立实参的拷贝,提高程序运行效率。
1.8静态成员
1.8.1静态成员变量
静态成员变量:
对象的静态数据成员,为各对象所共有,而不属于某个对象的成员,所有对象都可以应用他。
它在内存中只占一份空间。
它不随对象的建立而分配空间,也不随对象的撤销而释放。
在类中,即使不定义对象,也为静态数据成员分配空间,它可以被引用。
有了静态数据成员,各对象之间的数据有了沟通的渠道,实现数据共享,因此可以不使用全局变量。
(全局变量破坏了封装的原则,不符合面相对象程序的要求)
classBox
{
public:
staticintheight;
......
};
intBox:
:
height=10;//静态数据成员可以初始化,但只能在类体外进行初始化。
Boxa(15,20);
a.height=30;//静态数据成员既可以通过对象名引用,也可以通过类名来引用。
1.8.2静态成员函数
静态成员函数:
和静态数据成员一样,静态成员函数是类的一部分,而不是对象的一部分,它没有this指针,因此决定了静态成员函数不能访问本类中的非静态成员。
classBox
{
public:
staticintvolume();
......
};
classa(15,20);
两种访问方式:
Box:
:
volume();
a.volume;
1.9友员函数和友员类
在本类以外的其他地方定义的函数(这个函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数),在类体中用friend对其进行声明,此函数就成为本类的友员函数。
友员函数可以访问这个类中的私有成员。
正如把本家庭的某人确认为好友,允许他进入家里的各房间。
可以将一个类(例如B类)声明为另一个类(例如A类)的“朋友”,这时B类就是A类的友员类,可以访问A类中的所有成员。
(在A类的定义体中friendB;)
友员函数:
classTime
{
public:
voiddisplay(Date&);
......
};
classDate
{
public:
friendvoidTime:
:
display(Date&);//声明Time中的display函数为友员成员函数,在Time类中可以访问类Date中的私有成员变量。
private:
intmonth,day,year;
......
}
voidTime:
:
display(Date&d)
{
cout< ...... } 2三大特征 2.1封装 将有关的数据和操作代码封装在一个对象中,形成一个基本单位,各个对象之间相互独立,互不干扰。 二是将对象中某些部分对外隐蔽,隐蔽内部细节,只留有少量接口,以便与外界联系,接受外界消息。 2.2继承 可以利用一个已有的类建立一个新类,重用已有软件中的一部分甚至大部分 继承: “isa” 组合(子对象): “hasa” 派生类的声明方式: classStudent1: publicStudent { ...... } 继承方式有公用继承、保护继承、私有继承,一般都使用公用继承。 私有继承: 保护继承: 多重继承: 一个类有两个或多个基类,就是多重继承。 多重继承会引起二义性 在下图情况下,D类中存放了基类中的数据成员多份拷贝(从B、C类中继承而来) 解决方法是使用虚基类: classA {......}; classB: virtualpublicA {......}; classC: virtualpulbicC {......}; classD: publicB,publicC {......}; 使用多重继承时要非常小心,经常出现二义性问题,程序容易陷入迷魂阵,程序的编写、调试和维护都变得更加困难,因此,许多专业人员认为,不要提倡在程序中使用多重继承,只有在比较简单和不易出现二义性的情况或实在必要时才使用多重继承。 (java就不支持多重继承) 基类与派生类的转换: 基类与派生类对象之间有赋值兼容关系,由于派生类中包含从基类继承的成员,因此可以将派生类的值付给基类对象,在用到基类对象的时候,可以用其之类对象替代。 一是: 派生类对象可以向基类对象赋值 Aa1; //定义基类A对象a1 Bb1; //定义类A的公用派生类B的对象b1 a1=b1;//用派生类B对象b1对基类对象a1赋值 二是: 派生类对象可以向基类对象的引用进行赋值或初始化。 A&r=a1;//定义基类A对象的引用变量r,并用a1对其初始化 也可改为: A&r=b1;//定义基类A对象的引用变量,并用派生类B对象b1对其初始化 或保留A&r=a1;面对r重新赋值: r=b1; //用派生类B对象b1对a1的引用变量r赋值 三是: 如果函数的参数是基类对象或基类对象的引用,相应的实参可以用子类对象。 voidfun(A&r) {cout< 可以用为: fun(b1); 四是: 派生类对象的地址可以赋给指向基类对象的指针变量,也就是说,指向基类对象的指针变量也可以指向派生类对象。 2.3多态 几个相似而不完全相同的对象,在向他们发出同一消息时,他们的反应各不相同,分别执行不同的操作。 2.3.1静态多态 在编译期决定你应该调用哪个函数的行为是静态绑定(static-binding),这种现象就是静多态。 函数重载、模板、运算符重载,属静态多态,程序编译时系统就能决定调用哪个函数,因此又称编译时的多态性。 类模板与函数模板 类模板 有两个或多个类,其功能相同,仅仅是数据类型不同,则可以用类模板解决。 由于类模板包含类型参数,因此又称为参数化的类。 类模板是类的抽象,类是类模板的实例。 利用类模板可以建立含各种数据类型的类。 注意: 模板类的函数声明和实现必须都在头文件中完成,不能像普通类那样声明在.h文件中实现在.cpp文件中 ...... template classCompare { public: Compare(numtypea,numtypeb) { x=a;y=b; } numtypemax(); numtypemin() { return(x x: y; } private: numtypex,y; }; template numtypeCompare : max() { return(x>y)? x: y; } intmain() { Compare cout< "< Compare cout< "< return0; } 模板类的类型参数可以有一个或多个,每个类型前面都必须加class,如: template classmyclass {......}; 函数模板 建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。 这个通用函数就称为函数模板。 template Tmax(constT&lsh,constT&rhs) { return(lsh>rhs)? lsh: rhs; } 使用 inta=3;intb=4; cout< floatc=2.4;floatd=1.2; cout< 确定函数的过程也发生在编译器,当你使用max(a,b),编译器发现只有两个参数,那么就调用只有两个参数的函数版本,当使用max(a,b,c)时,编译器则使用有3个参数的版本。 通过上面的两个例子,你还可以使用更为方便的模板函数重载: template Tmax(constT&lsh,constT&rhs) { return(lsh>rhs)? lsh: rhs; } template Tmax(constT&a,constT&b,constT&c) { returnmax(max(a,b),c); } 使用 floata=3.6,b=1.2,c=7.8; cout< 函数的摸版就是函数定义的时候带有摸版功能但是没有实力化它只是一个空壳子。 模版函数就是调用的时候这时给它传递了实力化的类型如 函数重载 运算符重载 重载运算符函数作为类成员函数: 当表达式第一个参数(即运算符左侧的操作数)是该类对象,就可以定义为类成员函数,它可以通过this指针自由地访问本类的数据成员,因此可以少写一个函数的参数。 classComplex { Complexoperator+(Complex&c2);//声明重载运算符的函数。 ...... }; ComplexComplex: : operater+(complex&c2) { ...... } Complexc1,c2,c3; c3=c1+c2; C++编译系统解释为: c1.operator+(c2); 重载运算符函数作为友员函数: 当表达式第一个参数不是该类对象,则运算符重载函数不能作为成员函数,只能作为非成员函数。 如果函数需要访问类的私有成员,则必须声明为友员函数。 classComplex { friendComplexoperator+(int&i,Complex&c2);//声明重载运算符的函数为该类的友员函数,第一个参数不是该类对象,该函数也不是该类的成员函数,而是友员函数。 ...... }; Complexoperater+(int&i,complex&c2) { ...... } inti1; Complexc2,c3; c3=i1+c2; C++编译系统解释为: operator+(i1,c2); 思考: 能不能定义成: Complex&operator+(int&i,complex&c2)? 注意: C++规定, 必须定义为类的成员函数的运算符: 赋值、下标、函数调用 不能定义为类的成员函数的运算符: <<、>>、类型转换 由于友员函数的使用会破坏类的封装,因此原则上尽量将运算符函数作为成员函数。 但考虑到各方面的因素,一般将单目运算符重载为成员函数,将双目运算符重载为友员函数。 单目运算符重载: 如”++“运算符,前置自增运算符和后置自增运算符,他们的作用是不一样的,在重载中如何区分? classTime { ...... Timeoperator++();//声明前置自增运算符“++”重载函数 Timeoperator++(int);//增加一个int型形参,代表声明后置自增运算符“++”重载函数 ...... }; TimeTime: : operator++() { if(++sec>=60){sec-=60;++minute;} return*this; } TimeTime: : operator++(int) { Timetemp(*this); sec++;if(sec>=60){sec-=60;++minute;} returntemp; } 重载流插入运算符"<<"和流提取运算符">>": istream&operator>>(istream&,自定义类&); ostream&operator<<(ostream&,自定义类&); 重载流运算符第一个参数和函数的类型都必须是istream&或ostream&,因此只能将重载函数作为友员函数或普通的函数,而不能将他们定义为成员函数。 类型转换函数: 转换构造函数可以将一个指定类型的数据转换为类的对象。 反过来,用类型转换函数可以将一个类的对象转换为一个其他类型的数据。 classComplex { operatordouble()//将Complex类对象转换为一个double类型。 类型转换函数只能作为成员函数不能作为友员函数或普通函数。 { //double就是函数名,在函数名前不能指定函数类型,函数没有参数。 returnreal;//其返回值类型是由函数名中指定的类型名来确定的。 } ...... } 不能重载的运算符只有5个: .(成员访问运算符) .*(成员指针访问运算符) : : (域运算符) sizeof(长度运算符) ? : (条件运算符) 2.3.2动态多态 在运行期决定应该调用哪中类型对象的函数的行为是动态绑定(dynamic-binding),这种现象就是动多态! 动多态则是通过继承、虚函数(virtual)、指针或引用来实现。 虚函数 虚函数用于多态。 在基类中用virtual声明成员函数为虚函数,则在派生类中重定义此函数,为他赋予新功能。 在类外定义虚函数时,不必在加上virtual。 在派生类中重新定义此函数,要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数相同,并根据派生类的需要重新定义函数体。 C++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。 因此派生类重新声明该虚函数时,可以加上virtual,也可以不加。 但习惯上一般在每一层声明该函数时都加virtual,使程序更加清晰。 纯虚函数 在声明虚函数时被“初始化”为0的函数。 virtualfloatarea()const=0; 凡是包含纯虚函数的类都是抽象类。 抽象类不能定义对象(或者说抽象类不能实例化),但是可以定义指向抽象类数据的指针变量。 3与C语言相同处 3.1语法、变量、基本数据类型、语句、数组、结构、指针、函数等 3.2C++支持C 3.3编辑、编译、链接过程相同 3.4堆和栈的使用相同 3.5变量作用域 从作用域来看: 局部变量 1、自动变量(离开函数,值就消失) 2、静态局部变量(离开函数,值仍保留) 3、寄存器变量(离开函数,值就消失) 4、形式参数(可以定义为自动变量或寄存器变量) 全局变量 1、静态外部变量(从变量的定义处开始,到本程序文件的末尾) 2、外部变量(即非静态的外部变量,用extern声明,允许其他文件引用) 4与C语言的区别 4.1面相过程与面相对象 C面相过程: 程序=算法+数据结构 C++面相对象: 程序=对象s+消息 面相过程的结构化的软件工程: 设计思路: 采用自顶向下、逐步求精。 采用模块分解与功能抽象,自顶向下、分而治之。 程序结构: 按功能划分为若干个基本模块,形成一个树状结构。 各模块间的关系尽量可能简单,功能上独立;每一模块内部均是由顺序、选择和循环三种基本结构组成
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C+ 学习 笔记