学习总结

学习总结
壹、 第八章 运算符重载
1、 运算符可以看作是一种特殊的函数(因此运算符可以重载),操作数是函数的参数。参数表:提供参与运算的操作数;函数体:进行运算,返回运算结果,即表达式的值(运算结果是函数的返回值)。
2、 已见过的运算符重载现象移位运算符>>和<<,用作流输入和输出运算符。
⑴ 如果希望用户自定义类型以这种方式输入和输出,就需要重载“>>”和“<<”。注意:用户自定义类型只能用非成员函数的形式重载这两个运算符。
⑵ 输入输出运算符的函数原型:
istream& operator>>(istream&, type&);
ostream& operator<<(ostream&, const type&);
3、 运算符函数的函数名由关键字operator 和其后要定义的运算符组成,例如:operator+、operator>> 。
4、 运算符函数的参数个数取决于:①运算符的操作个数,即是一元运算符还是二元运算符;②运算符函数是成员函数还是非成员函数。
5、 ⑴类的成员运算符函数
this 指向的对象被作为运算符的第一个操作数(左),一元运算符函数不需要提供参数;重载二元运算符时,当前对象(this指向的对象)作为左操作数,只需要提供一个参数作为右操作数。
⑵非成员运算符函数
一元运算符要提供一个类类型的参数;二元运算符需要提供两个参数分别作为左、右操作数,其中至少一个参数必须是类类型的。通常声明为类的友元,以便访问私有数据成员。
6、 ⑴不能滥用运算符重载,只有在能使类的代码更易读、使类对象的操作方式更符合一般习惯时,才重载运算符;运算符重载不会改变内置类型的表达式中运算符的含义。
⑵以下运算符不建议重载:逻辑与(&&)、逻辑或(||)、逗号运算符(,)、取地址运算符(&)
7、 设计类时,只有操作是类需要的,且在逻辑上与运算符相关,才适合定义成重载的运算符:
如果类执行I/O 操作,可以定义移位运算符>>和<<;
如果类的某个操作是检查相等性,则定义operator==;这时候通常也应该有operator!=;
如果类包含内在的单序比较操作,则定义operator<;此时也应该有其他关系操作;
重载运算符的返回类型通常情况下应该与内置版本的返回类型兼容,(逻辑运算符和关系运算符应该返回bool值);
如果类定义了赋值运算符,同时还定义了算术运算符或位运算符,那么最好也提供对应的复合赋值运算符
8、 定义运算符函数时成员函数与非成员函数的选用:
① 赋值(=)、下标([])、函数调用(())和成员函数访问箭头(->)运算符必须是成员函数;
② 复合赋值运算符一般应该是成员,但并非必须;
③ 改变对象状态的运算符或者与给定类型密切相关的运算符,如自增、自减和解引用运算符,通常应该是成员;
④ 具有对称性的运算符可能转换两个操作数中的任何一个,如算术、关系和位运算符等,通常应该是非成员函数;
⑤ 重载移位运算符<<和>>用于对象的I/O 操作时,左操作数是标准库流对象,右操作数才是类类型的对象,只能用非成员函数
9、 运算符函数的参数与返回类型
① 普通算术运算符呵关系运算符都不会改变参数,当运算符函数是类的成员函数时,将其定义为const成员函数。
② 返回值的类型取决于运算符的具体含义。
③ 所有运算符均改变左值。
④ 逻辑运算符和关系运算符最好返回bool值,也可以返回int值或者由typedef定义的等价类型。
10、 重载下标运算符:有些类的对象可以像数组一样操作,可以为这样的类提供下标运算。下标运算符operator[]必须是成员函数,它只接收一个参数,通常是整值类型。下标运算符返回一个元素的引用,以便用作左值。
11、 函数调用运算符
如果类重载了函数调用运算符operator(),就可以像使用函数一样使用该类的对象。因为类同时能存储状态,所以比普通函数更灵活。函数调用运算符是唯一不限制操作数个数的运算符。
函数调用运算符必须是成员函数。一个类可以定义多个不同版本的调用运算符,但是必须在参数个数或类型上有所区别。
12、 函数对象
如果一个类定义了函数调用运算符,那么该类的对象称为函数对象,或者仿函数(functor)。因为可以调用这种对象,在代码层面感觉跟函数的使用一样,但本质上并非函数。
贰、第九章 组合与继承
一、对象成员与组合成员
1、 将一个类的对象作为另一个类的成员,被称作组合或包含。组合一个已有类的对象作为新类的成员被称为按值组合。
2、 组合关系的特点是成员对象是组合对象的一部分,随着组合对象的创建而创建,随着组合对象的撤销而撤销,成员对象不作为独立元素对外部展现。
3、 对象成员的初始化:
创建包含对象成员的组合对象时,会执行成员类的构造函数初始化对象成员。成员对象的初始化使用初始化列表语法。
当组合对象被撤销时,会执行其析构函数,成员对象的析构函数也会被执行。析构函数的执行次序和构造函数相反,即先执行组合对象的析构函数,再执行成员函数的析构函数。
二、 继承
1、 继承:在已有类的基础上创建新类的过程。 一个 B 类继承A类,或称从类 A 派生类 B。
2、 继承是面向对象的核心特征之一,也是一种复用已有类的机制。在已有类的基础上继承得到新类型,这个新类型自动拥有已有类的特性,并可以修改继承到的特性或者增加自己的新特性。
被继承的已有类成为基类;继承得到的新类称为派生类;派生类可以再被继承,这样构成的层次结构称为继承层次。
3、 派生类继承了基类的数据成员和成员函数,只需要对自己不同于基类的行为或扩展的行为编写代码。
类继承关系的语法形式:
class 派生类名字:[访问限定符]基类名字
{
数据成员和成员声明
};
4、 基类名表构成
访问控制 基类名1,访问控制 基类名2,…,访问控制 基类名n
访问控制 表示派生类对基类的继承方式,使用关键字:
public 公有继承
private 私有继承
protected 保护继承
5、 派生类成员的访问控制:
不论种方式继承基类,派生类都不能直接使用基类的私有成员 。在公有派生类中,基类的public成员和protected成员被继承,分别作为派生类的public成员和protected成员。基类的private成员虽被继承了,但在派生类中是不可见的。
6、 派生类的生成过程经历了三个步骤:
①吸收基类成员(全部吸收(构造、析构除外),但不一定可见):在C++的继承机制中,派生类吸收基类中除构造函数和析构函数之外的全部成员。
②改造基类成员:通过在派生类中定义同名成员(包括成员函数和数据成员)来屏蔽(隐藏)在派生类中不起作用的部分基类成员。
③添加派生类新成员:仅仅继承基类的成员是不够的,需要在派生类中添加新成员,以保证派生类自身特殊属性和行为的实现。
7、 重名函数:
例:
class base
{ public :
int a , b ;
} ;
class derived : public base
{ public :
int b , c ;
} ;
void f ()
{ derived d ;
d . a = 1 ;
d . base :: b = 2 ;
d . b = 3 ;
d . c = 4 ;
};
派生类定义了与基类同名的成员,在派生类中访问同名成员时屏蔽(hide)了基类的同名成员。在派生类中使用基类的同名成员,显式地使用类名限定符:
类名 :: 成员
#include
using namespace std ;
class A
{ public:
int a1, a2 ;
A( int i1=0, int i2=0 ) { a1 = i1; a2 = i2; }
void print()
{ cout << “a1=” << a1 << ‘\t’ << “a2=” << a2 << endl ; }
};
class B : public A
{ public:
int b1, b2 ;
B( int j1=1, int j2=1 ) { b1 = j1; b2 = j2; }
void print() //定义同名函数
{ cout << “b1=” << b1 << ‘\t’ << “b2=” << b2 << endl ; }
void printAB()
{ A::print() ; //派生类对象调用基类版本同名成员函数
print() ; //派生类对象调用自身的成员函数
}
};
int main()
{ B b ; b.A::print(); b.printAB(); }

8、 派生类中访问静态成员:
派生类中访问静态成员,用以下形式显式说明:
类名 :: 成员
或通过对象访问 对象名 . 成员
9、 基类的初始化:
在创建派生类对象时用指定参数调用基类的构造函数来初始化派生类继承基类的数据。派生类构造函数声明为:
派生类构造函数 ( 变元表 ) : 基类 ( 变元表 ) , 对象成员1( 变元表 )
… 对象成员n ( 变元表 ) ;
构造函数执行顺序:基类  对象成员 派生类
10、 派生类构造函数和析构函数的定义规则:
▲派生类构造函数和析构函数的使用原则
① 基类的构造函数和析构函数不能被继承
② 如果基类没有定义构造函数或有无参的构造函数, 派生类也可以不用定义构造函数
③ 如果基类无无参的构造函数,派生类必须定义构造函数
④ 如果派生类的基类也是派生类,则每个派生类只负责直接基类的构造
⑤ 派生类是否定义析构函数与所属的基类无关
11、 派生类构造函数的定义:
在C++中,派生类构造函数的一般格式为:
派生类::派生类名(参数总表):基类名(参数表)
{
// 派生类新增成员的初始化语句
}
注意:这是基类有构造函数且含有参数时使用
12、 派生类的析构函数:
⑴ 当派生类中不含对象成员时
① 在创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数;
② 在撤消派生类对象时,析构函数的执行顺序是:派生类的析构函数→基类的析构函数。
⑵ 当派生类中含有对象成员时
① 在定义派生类对象时,构造函数的执行顺序:基类的构造函数→对象成员的构造函数→派生类的构造函数;
② 在撤消派生类对象时,析构函数的执行顺序:派生类的析构函数→对象成员的析构函数→基类的析构函数。
三、 多继承
1、 一个类有多个直接基类的继承关系称为多继承
多继承声明语法为:
class 派生类名 : 访问控制 基类名1 , 访问控制 基类名2 , … , 访问控制 基类名n
{
数据成员和成员函数声明
};
类 C 可以根据访问控制同时继承类 A 和类 B 的成员,并添加自己的成员。
2、 多继承的派生类构造与访问 :
① 多个基类的派生类构造函数可以用初始式调用基类构造函数初始化数据成员。
② 执行顺序与单继承构造函数情况类似。多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序。
③ 一个派生类对象拥有多个直接或间接基类的成员。不同名成员访问不会出现二义性。如果不同的基类有同名成员,派生类对象访问时应该加以识别。
3、 多继承的构造函数:
派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),…,基类名n(参数表n)
{
// 派生类新增成员的初始化语句
}
多继承方式下构造函数的执行顺序:
●先执行所有基类的构造函数
●再执行对象成员的构造函数
●最后执行派生类的构造函数
处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的基类顺序。与派生类构造函数中所定义的成员初始化列表顺序没有关系。内嵌对象成员的构造函数执行顺序与对象在派生类中声明的顺序一致。
4、 多继承的析构函数:
●析构函数名同样与类名相同,无返回值、无参数,而且其定义方式与基类中的析构函数的定义方式完全相同。
●功能是在派生类中对新增的有关成员进行必要的清理工作。
●析构函数的执行顺序与多继承方式下构造函数的执行顺序完全相反,首先对派生类新增的数据成员进行清理,再对派生类对象成员进行清理,最后才对基类继承来的成员进行清理。
5、 何时可以使用继承,何时又该使用组合?
① 如果多个类共享数据而非行为,应该创建这些类可以包含的共用对象
② 如果多个类共享行为而非数据,应该让它们从共同的基类继承而来,并在基类里定义共用的操作
③ 如果多个类既共享数据也共享行为,应该让它们从一个共同基类继承而来,并在基类里定义共用的数据和操作
④ 如果想由基类控制接口,使用继承;如果想自己控制接口,使用组合。
6、 当决定使用继承时,必须要做出如下决策
① 对每个数据成员而言,它应该对派生类可见吗?
通过访问限定可以控制成员在派生类中的可见性
② 对于每个成员函数而言,它应该对派生类可见吗?应该有默认实现吗?默认的实现可以被覆盖吗?
覆盖与隐藏和下一章将要讨论的虚函数与抽象类等机制可以为此提供技术上的支持。
7、 关于继承层次要注意的问题
① 不要创建任何并非绝对必要的继承结构,例如,只有一个派生类的基类。
② 在继承层次中,将公共接口、数据及操作放到尽可能高的位置,以便派生类使用
③ 避免让继承层次过深
叁 、第十章 虚函数与多态性
一、
1、 虚函数和动态联编:
① 冠以关键字 virtual 的成员函数称为虚函数。声明虚函数的语法形式:
Virtual 返回类型 成员函数名(参数表);
② 实现运行时多态的关键首先是要说明虚函数,另外,必须用基类指针调用派生类的不同实现版本
2、 多态性(Polymorphism)是指一个名字,多种语义;或界面相同,多种实现。重载函数是多态性的一种简单形式。虚函数允许函数调用与函数体的联系在运行时才进行,称为动态联编。
3、 虚函数与基类指针:
① 一个虚函数,在派生类层界面相同的重载函数都保持虚特性
② 虚函数必须是类的成员函数
③ 虚函数可以是另一个类的友元
④ 析构函数可以是虚函数,但构造函数不能是虚函数
4、 虚函数的重载特性:
① 在派生类中重载基类的虚函数要求函数名、返回类型、参数个数、参数类型和顺序完全相同
② 如果仅仅返回类型不同,C++认为是错误重载
③ 如果函数原型不同,仅函数名相同,丢失虚特性
▲注意:
•派生类应该从它的基类公有派生。
•必须首先在基类中定义虚函数。
•派生类对基类中声明虚函数重新定义时,关键字virtual可以不写。
•一般通过基类指针访问虚函数时才能体现多态性。
•一个虚函数无论被继承多少次,保持其虚函数特性。
•虚函数必须是其所在类的成员函数,而不能是友元函数,也不能是静态函数。
•构造函数、内联成员函数、静态成员函数不能是虚函数。
(虚函数不能以内联的方式进行处理)
•析构函数可以是虚函数,通常声明为虚函数。
5、 纯虚函数与抽象类:
① 纯虚函数是一个在基类中说明的虚函数,在基类中没有定义, 要求任何派生类都定义自己的版本
② 纯虚函数为各派生类提供一个公共界面
③ 纯虚函数说明形式:
virtual 类型 函数名(参数表)= 0 ;
④ 一个具有纯虚函数的基类称为抽象类。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值