面向对象程序设计¶
课程链接:程序设计与算法(三)C++面向对象程序设计_北京大学_中国大学MOOC(慕课) (icourse163.org)
笔记时间:24年寒假
1.从C到CPP¶
引用¶
- const & 不允许通过该引用来修改对象内容
- const T & 和T & 是不同的类型,不能用const T &来初始化T &
- 同理,常量指针不能通过其修改指向的内容
动态内存分配¶
- new出来的对象必须要delete才会消失,只能delete一次
- 返回起始地址的指针
Tip
delete [] p;
内联、重载、缺省¶
- 避免二义性
2.类和对象基础¶
类的成员¶
- private
- public
-
protected
-
缺省认为是私有成员
构造函数 constructor¶
- 名字与类名相同,可以有参数,不能有返回值
- 作用是对对象进行初始化,生成对象时自动调用
- 没写默认无参构造函数,不做任何操作,如果定义了则默认的函数不存在
- 一个类可以有多个构造函数
Tip
注意在数组中的使用
复制构造函数¶
- 只有一个参数
- 形如X::X(X&) 或 X::X(const X &)
- 复制构造函数有三种情况起作用
- 当用一个对象去初始化另一个对象
- 一个函数的参数是类A的对象,当该函数调用时
- 返回值是类A的对象,当函数返回时
Tip
在不同编译器中可能有不同表现
类型转换构造函数¶
- 目的是实现类型的自动转换
- 只有一个参数,且不是复制构造函数,可以看做是转换构造函数
析构函数¶
- 名字与类名相同,在前面加一个
~
,没有参数和返回值,一个类最多一个析构函数 - 在对象消亡时被自动调用,完成善后工作
3.类与对象提高¶
this指针¶
- 作用是指向成员函数所作用的对象
- 静态成员函数中不能使用this指针,因为静态成员函数并不具体作用于某个对象,因此静态成员函数的真实的参数的个数,就是程序中写出的参数个数
静态成员¶
- 访问静态成员
- 类::成员名
- 对象名.成员名
- 指针->成员名
- 引用.成员名
-
静态成员变量本质上是全局变量,对象不存在,静态成员变量也存在;静态成员函数是全局函数
-
静态成员函数,不能访问非静态成员变量,不能调用非静态成员函数。(因为不能确定是哪个象的)
Tip
1. 注意对静态成员变量的初始化; 2. 注意复制构造函数。
成员对象和封闭类¶
- 有成员对象的类叫封闭类
- 任何生成封闭类对象的语句都要让编译器明白,对象中的成员对象,是如何初始化的
- 初始化列表
- 先执行所有对象成员的构造函数,再执行封闭类的构造函数,构造函数调用次序和在类中的说明次序一致
- 封闭类对象消亡事,先执行封闭类的析构函数,再执行成员对象的析构函数,次序和构造函数调用次序相反
常量对象,常量成员函数、常引用¶
- 常量成员函数执行期间不能修改其所 作用的对象。因此不能修改成员变量的值(静态除外),也不能调用非常量成员函数(静态除外)
- 常量对象可以执行常量成员函数
- 两个成员函数,名字和参数表一样,一个是常量一个不是,则为重载
- 将对象的常引用作为函数参数,不会触发复制构造函数,也不会修改对象实参的值
友元¶
- 友元函数不是成员函数,一个类的友元函数可以访问该类的私有成员
- A是B的友元类,那么A的成员函数可以访问B的私有成员
4.运算符重载¶
基本概念¶
- 运算符重载实质是函数重载,可以重载为普通函数或者成员函数。把函数运算符的表达式转换成对运算符函数的调用,操作数转换成运算符函数的参数。多次重载时根据实参类型决定调用函数
- 重载为 成员函数时,参数个数是运算符目数;重载为普通函数时,参数个数是运算符目数
赋值运算符'='重载¶
- 只能重载为成员函数
Tip
注意浅拷贝和深拷贝问题
运算符重载为友元函数¶
- 一般情况下,将运算符重载为类的成员函数,是较好的选择。
- 有时需要设置成普通函数,但普通函数又不能访问私有成员,所以需要把运算符重载为友元
可变长数组类的实现¶
- 略(vector)
流插入运算符和流提取运算符的重载¶
- 由于不能修改iostream里的对象,重载只能重载为全局函数
类型转换运算符的重载¶
自增自减运算符重载¶
class CDemo{
private :
int n;
public:
CDemo(int i=0):n(i){}
CDemo & operator++(); //前置
CDemo operator++(int); //后置
operator int () {return n;};
friend CDemop & operator--(CDemo &);
friend CDemo operator--(CDemo &, int);
};
CDemo & CDemo::operator++() //前置++
{
n ++;
return * this;
} //++s即s.operator++();
CDemo CDemo::operator++(int k) //后置++
{
CDemo tmp(*this);
n++;
return tmp;//返回修改前的对象
} //s++即s.operator++(0);
CDemo & operator--(CDemo & d) //前置--
{
d.n--;
return d;
} //s--即operator--(s)
CDemo operator--(CDemo & d, int) //后置--
{
CDemo tmp(d);
d.n--;
return temp;
} //s--即operator--(s,0)
5.继承¶
继承和派生的基本概念¶
- 继承:在定义一个新的类B时,如果该类与某个已有的类A相似(指B拥有A的全部特点),那么就可以把A作为一个基类,而把B作为基类的一个派生类(或子类)。
- 派生类是通过对积累进行修改和扩充的得到的,在派生类中,可以扩充新的成本员变量和成员函数
- 派生类一经定义后,可以独立使用,不依赖于基类
- 派生类拥有基类的全部成员函数和成员变量,在派生类的各个成员函数中,不能访问基类中的private成员
- 写法:class 类名:public 基类名
继承关系和复合关系¶
-
继承:”是“关系
-
基类A,B是基类A的派生类
-
逻辑上要求:一个B对象也是是一个A对象
-
复合:“有”关系
-
类C中有成员变量k,k是类D的对象,则C和D是复合关系
-
逻辑上要求:D对象是C对象的固有属 性或组成部分
-
人狗问题:
覆盖和保护成员¶
- 派生类中可以定义一个和基类成员同名的成员,叫覆盖。在派生类中访问这类成员,缺省的情况是访问派生类的成员。要在派生类中访问基类定义的同名成员时,要使用作用域符号 ::
- protected成员:可以被 基类的成员函数,基类的友元函数 访问(同private),另外派生类的成员函数 可以访问 对象的基类的保护成员 访问
派生类的构造函数¶
-
创建派生类对象时,要调用基类构造函数,来初始化派生类对象中从基类继承的成员。 总是先执行基类构造函数,再执行派生类构造函数。
-
调用基类构造函数两种方式
- 显式方式:在派生类的构造函数中,为积累的构造函数提供参数
- 隐式方式:在派生类构造函数中,省略积累构造函数时,派生类的构造函数自动调用基类的默认构造函数
- 派生类的析构函数被执行时。先执行派生类的析构函数,再调用基类的析构函数
- 封闭派生类的构造函数
- 先执行基类的构造函数
- 再执行成员对象类的构造函数
- 最后执行派生类自己的构造函数
- 析构函数相反顺序
公有继承的赋值兼容规则¶
- 派生类对象可以赋值给基类对象
- 派生类对象可以初始化基类引用
- 派生类对象的地址可以赋值给基类指针
继承方式不是上述public则上述三条不成立
- 直接基类和间接基类
- 在声明派生类时只需要列出他的直接基类
- 构造函数执行从最顶层基类开始,一直到当前派生类,析构函数相反
多态¶
虚函数和多态的基本概念¶
-
在类的定义中,前面有virtual关键字的成员函数就是虚函数
-
c++ class base{ virtual int get(); }; int base::get(){ }
-
virtual关键字只用在类定义的函数声明中,写函数体时不用
-
构造函数和静态成员函数不能是虚函数
-
多态表现形式一
-
派生类的指针可以赋值给基类指针
-
通过基类指针调用基类和派生类中的同名虚函数时
- 若该指针指向一个基类的对象,那么被调用是基类的虚函数
- 若该指针指向一个派生类的对象,那么被调用的是派生来的虚函数
-
多态表现形式二
-
派生类的对象可以赋值给基类引用
-
通过基类引用调用基类和派生类中的同名虚函数中是
- 若该引用引用的是一个基类的多想,那么被调用的是基类的虚函数
- 若该引用引用的是一个派生类的对象,那么被调用的是派生类的虚函数
-
在非构造函数,非析构函数的成员函数中调用虚函数,就是多态;在构造函数和析构函数中调用虚函数,不是多态:编译时就可以确定,调用的函数是自己的类或者基类中定义的函数。
多态的实现原理¶
- 多态关键在于通过基类指针或引用调用一个虚函数时,编译时不确定调用的是基类还是派生类的函数,运行时才确定,这叫“动态联编”。
- 虚函数表
虚析构函数、纯虚构函数和抽象类¶
-
-
纯虚函数:无函数体
virtual void func() = 0
。 - 包含纯虚函数的类叫抽象类
- 从抽象类只能作为基类来派生新类使用,不能创建抽象类的对象
- 抽象类的指针和引用可以指向由抽象类派生出来的类的对象
- 在抽象类的成员函数内可以调用纯虚函数,但是在构造函数或析构函数内部不能调用纯虚函数
- 如果一个类从抽象类派生而来,那么当且仅当他实现了基类中的所有纯虚函数,他才能成为非抽象类
输入输出和模版¶
输入输出流相关的类¶
摆了