前言
总结整理不易,希望大家点赞收藏。
给大家整理了一下C++程序设计中的重点概念,以供大家期末复习和考研复习的时候使用。
C++程序设计系列文章传送门:
第一章 面向对象基础
第四/五章 函数和类和对象
第六/七/八章 运算符重载/包含与继承/虚函数和多态性
第九/十一/十二章 模板/输入/输出流/标准模板库
文章目录
- 前言
- [第六章 运算符重载](#第六章 运算符重载)
-
- [6.1 何时需要定义赋值运算符](#6.1 何时需要定义赋值运算符)
- [6.2 举例说出你所了解的必须以类成员方式定义的运算符](#6.2 举例说出你所了解的必须以类成员方式定义的运算符)
- [6.3 C++编译器为类自动产生的四个默认成员函数分别是什么](#6.3 C++编译器为类自动产生的四个默认成员函数分别是什么)
- [第七章 包含与继承](#第七章 包含与继承)
-
- [7.1 包含和继承是面向对象语言提供的两种重要的代码复用机制阐述它们有什么区别如何选择应用](#7.1 包含和继承是面向对象语言提供的两种重要的代码复用机制阐述它们有什么区别如何选择应用)
- [7.2 继承等级是什么?](#7.2 继承等级是什么?)
- [7.3 继承中的类的赋值兼容原则](#7.3 继承中的类的赋值兼容原则)
- [第八章 虚函数和多态性](#第八章 虚函数和多态性)
-
- [8.1 什么是虚函数?什么是纯虚函数?为什么引入虚函数和纯虚函数?](#8.1 什么是虚函数?什么是纯虚函数?为什么引入虚函数和纯虚函数?)
- [8.2 析构函数应该是虚函数吗?为什么?](#8.2 析构函数应该是虚函数吗?为什么?)
- [8.3 为什么默认的析构函数不是虚函数?](#8.3 为什么默认的析构函数不是虚函数?)
- 练手题
- 下一章传送门
第六章 运算符重载
6.1 何时需要定义赋值运算符
如果一个类需要进行赋值操作,就需要定义赋值运算符。
cpp
class MyClass {
public:
MyClass& operator=(const MyClass& other) { // 实现赋值操作的代码
return *this;
}
};
对于含有指针成员的类来说,使用默认的赋值运算符可能会导致指针的浅拷贝问题。在这种情况下,需要自定义赋值运算符,以确保指针的深拷贝,避免出现潜在的内存泄漏和错误。
6.2 举例说出你所了解的必须以类成员方式定义的运算符
赋值运算符(=)、下标运算符([])、函数调用运算符(())、成员访问运算符(->)。这些运算符必须被定义为成员函数的原因是它们需要访问类的私有成员,只有成员函数才能访问类的私有成员。另外,它们的左操作数都是类的对象,因此只有成员函数才能访问对象的成员。
6.3 C++编译器为类自动产生的四个默认成员函数分别是什么
默认成员函数包括默认构造函数、析构函数、拷贝构造函数和拷贝赋值运算符。
cpp
Mystring(const char* str=nullptr);
~Mystring();
Mystring(const Mystring& other); // 要进行深拷贝
Mystring& operator=(const Mystring& other); //重载操作符
第七章 包含与继承
7.1 包含和继承是面向对象语言提供的两种重要的代码复用机制阐述它们有什么区别如何选择应用
包含是指在一个类中嵌入另一个类的对象,通过调用该对象的方法来实现功能复用。这种方式可以实现代码的模块化和灵活性,但需要手动管理对象的生命周期和内存分配。
继承是指一个类可以从另一个类继承属性和方法,从而实现代码的复用和扩展。这种方式可以减少代码的重复,提高代码的可维护性和可扩展性,但也可能导致代码的耦合度过高,难以维护和扩展。
在选择应用时,需要根据具体的需求和设计原则进行权衡。一般来说,如果需要实现简单的功能复用,可以选择包含;如果需要实现复杂的继承关系和代码复用,可以选择继承。
7.2 继承等级是什么?
公有继承(public inheritance):派生类可以访问基类的公有成员和保护成员,但不能访问基类的私有成员。
保护继承(protected inheritance):派生类可以访问基类的公有成员和保护成员,但不能访问基类的私有成员。
私有继承(private inheritance):派生类可以访问基类的公有成员和保护成员,但不能访问基类的私有成员。
虚拟继承(virtual inheritance):用于解决多重继承带来的问题,将同一基类的多个派生类共享同一个基类子对象,避免多次复制基类数据成员。防止菱形继承。class A; class B::virtual public A{}; class C::virtual public A{};
只要是父类中private成员无论以什么方式继承,儿子都无法访问;如果是公有继承儿子中的访问权限不变;如果是保护继承,儿子中父亲除了private成员其余均为protected成员;如果是私有继承,均为private成员。
子类不会继承父类的构造函数、析构函数和赋值操作符
7.3 继承中的类的赋值兼容原则
1、子类对象可以当作父类的对象使用(子类是特殊的父类)
2、子类对象可以直接赋值父类对象
3、子类对象可以直接初始化父类对象
4、父类指针可以直接指向子类对象
5、父类引用可以直接引用子类对象
第八章 虚函数和多态性
8.1 什么是虚函数?什么是纯虚函数?为什么引入虚函数和纯虚函数?
被 virtual 关键字修饰的成员函数称为虚函数。在虚函数后面添加 =0 ,虚函数就成为纯虚函数。纯虚函数只是一个接口,它的具体实现需要由子类来完成,子类必须实现纯虚函数,否则子类也会变成抽象类。
引入纯虚函数可以将基类的某些函数强制为虚函数,并且必须被子类实现。引入虚函数和纯虚函数的目的在于实现多态性。通过定义虚函数和纯虚函数,可以使得子类可以覆盖基类中的函数,从而实现子类对于函数的重写和扩展。而通过运行时动态绑定的方式,可以根据对象的实际类型来确定调用相应的函数,从而实现多态性。
8.2 析构函数应该是虚函数吗?为什么?
当一个类被继承时,如果其析构函数不是虚函数,那么在使用基类指针或引用指向派生类对象并删除这个对象时,可能会导致只有基类部分被析构,派生类部分的资源没有被正确地释放,从而导致内存泄漏或者其它的错误。这是因为在这种情况下,编译器只会调用基类的析构函数,而不会调用派生类的析构函数,因为指针或引用的静态类型是基类类型,因此需要使用虚析构函数来确保正确地释放资源。
总之,如果一个类可能会被继承,那么就应该将其析构函数声明为虚函数,以确保正确释放派生类的资源。
8.3 为什么默认的析构函数不是虚函数?
当类中有虚成员函数时,类会自动进行一些额外工作。这些额外的工作包括生成虚函数表和虚表指针,虚表指针指向虚函数表。每个类都有自己的虚函数表,虚函数表的作用就是保存本类中虚函数的地址,我们可以把虚函数表形象地看成一个数组,这个数组的每个元素存放的就是各个虚函数的地址。当我们创建一个类时,系统默认我们不会将该类作为基类,所以就将默认的析构函数定义成非虚函数,这样就不会占用额外的内存空间。同时,系统也相信程序开发者在定义一个基类时,会显示地将基类的析构函数定义成虚函数,此时该类才会维护虚函数表和虚表指针。
练手题
9.1