编程手札:C++快速笔记

Author:雾雨霜星

Time:2021-09-25
我的网站:雾雨霜星

类与对象

类的声明与实例化

类的声明:

class Object
{public:Object();Object(Object & ob);Object(int,int,int);private:...protected:...
};

实例化(建立对象):

Object object;

访问特性

public:公有访问特性,在类外也可见

private:私有访问特性,只在类内可见

protected:保护访问特性,只在类内和派生类可见

成员函数的声明

成员函数在类外定义:

返回类型 类名::函数名(参数表){...}

成员函数在类内定义:此时编译器将其看作内联函数进行处理。

成员函数使用const修饰

在成员函数首部以const作为后缀的成员函数成为"常成员函数"。

特点:不能修改数据成员

// 在类内声明:
void Object:: PrintData()const;
// 在类外定义描述:
void Object:: PrintData()const{......
}

本质:此时的this指针是一个常指针,即其所指向的对象约束为只读,故对数据成员修改会引发错误。

数据成员

静态数据成员

声明/定义:使用关键字static声明的数据成员,只能在类外定义

特点:所有类的实例共用一个静态成员变量

class Student{static int count;public:......
}
int Student:: count=0;

上述代码的静态数据成员,没有在public字段内进行声明,属于是私有数据成员。

常数据成员

声明/定义:使用关键字const作为前缀的数据成员

特点:该数据成员为常量,且通过构造函数使用初始式进行初始化

构造函数与析构函数

构造函数:在一个类进行实例化的时候被自动调用的函数。

复制构造函数:通过传入一个该类的实例,复制该对象来创建新对象。

析构函数:在一个对象作用域结束时自动调用,或者调用去销毁对象。

// 构造函数
Object:: Object(){}
Object:: Object(int a, int b, int c){}
// 复制构造函数
Object:: Object(const Object & input_object){}
// 析构函数
Object:: ~Object(){}
复制构造函数:浅复制/深复制

浅复制:使用系统提供的复制构造函数(没有自定义的复制构造函数时)。

若数据成员是指针,系统复制对象的该数据成员时只是进行地址的复制,不会重新分配存储空间。

此时使用复制构造函数创建的新对象,其内的相应的指针数据成员与作为参数传入的对象的该数据成员共用一个存储空间(指针指向相同的地址)。

深复制:使用用户自定义的复制构造函数。

深复制可以避免浅复制中的指针数据不具有独立性的问题。

class Name
{public:Name(char* p);Name(const Name &Obj);......
}
Name obj1("name");
Name obj2 = obj1;//有自定义的复制构造函数,深复制。若无则调用系统浅复制。
构造函数参数初始式

形式:

构造函数名(变元表): 数据成员1(变元表),......, 数据成员n(变元表)
{......}

例如:

class Student()
{public:Student(int,int);private:const int a;Data data;
}
Student::Student(int a_value, int data_value):a(a_value),data(data_value)
{......}
//在主函数中调用
Student s(0, 1);

理解:所有的类型本质都是类,int也是类,上述的int a就是一个int对象。

this指针

对象使用成员函数:每个类的对象都有自己的存储空间,但是系统不会为每个类的对象建立成员函数的副本,即所有类的对象共用成员函数。

this指针:C++为每个成员函数提供一个this指针,当一个对象调用成员函数时,其this指针会指向这个类的对象。

this指针的使用:只可以在成员函数中显式使用,表示指向"当前对象"的指针。

友元

声明/定义:使用关键字firend作为前缀的成员函数或者类数据成员

特点:可以访问类的所有成员,包括私有成员

访问特性:可以看做是公有权限,不受在类中声明位置的影响

友元函数

必须在参数表总显式指明要访问的对象。

class Point
{public:friend void FriendFun(Point*,int,double,...);......
}
void FriendFUn(Point* p,int a,double b,...)
{......
}
// 在主程序中调用如下:
Point p;
FriendFUn(&p, 1, 0.5, ...);
友元类

在类中声明友元类后,该友元类可以访问这个类的私有成员。

class A
{public:friend class B;private:int x;
}
class B
{public:void int get(){return Aobj.x;}private A Aobj;
}

运算符重载

形式:

类型 类名::operator op(参数表)
{// 新的操作
}

类名:重载该运算符的类

op:运算符

通常会使用友元函数来重载运算符"+"、"-"、"*"、"/",方便计算中直接访问类的成员。

注意

  1. 不能被重载的运算符有:". “、”.*"、"::"、"?:" 、“sizeof”

  2. 另外不能用友元函数重载的运算符有:=、()、[]、->

  3. 重载++与–时,使用参数进行前置与后置的区别

    A & A::operator++(int)
    // 或者:
    friend A& operator ++(A&, int)
    

继承与多态

继承的描述

定义与程序形式

继承:在已经定义好的类的基础上定义新的类,这样定义的新的类具有原本定义好的类的所有成员,但是只要公有成员和保护成员可在新的类中可见。

上述中,"已经定义好的类"即基类,"新的类"即派生类。

程序形式如下:

class 派生类名 : 基类名表
{数据成员与成员函数说明
};

基类是已经定义好的类,其中的基类名表如下形式:

访问控制 基类名1, 访问控制 基类名2, 访问控制 基类名3, ... , 访问控制 基类名n
访问控制

访问控制:重新确定派生类中继承得到的原本基类的数据成员与成员函数访问权限。

  • public:公有继承,基类中的公有成员成为派生类中的公有成员,基类中的保护成员成为派生类中的保护成员。
  • private:私有继承,基类中的公有成员与保护成员成为派生类中的私有成员。
  • protected:保护继承,基类中的公有成员与保护成员成为派生类中的保护成员。

注意:基类中的私有成员,若非使用友元,在派生类中不可见。

继承的初始化过程

初始化顺序:先执行基类的构造函数,然后再执行派生类的构造函数

  • 注意:当继承多个类时,按照"基类名表"中基类从左至右的顺序执行基类的构造函数

构造函数传参:通过派生类的构造函数获取参数,将派生类构造函数获取到的参数,相应的分配给基类

派生类构造函数的参数初始式:

构造函数名(变元表):基类1(变元表),基类2(变元表),...,基类n(变元表),数据成员1(变元表),...,数据成员n(变元表)

注意,上述冒号后的先后顺序不重要,只要有出现并相应分配参数即可。

访问声明

用途:在访问控制的基础上对原本不可见的成员变为可访问的。

例如:使用了私有继承,但是想让某个基类成员在派生类中保持原本的访问权限,那么对该成员使用访问声明即可。

格式:在相应字段下,声明"基类名::成员"

注意事项:

  • 不可改变原本的数据类型
  • 不允许在派生类中降低或提升基类成员的可访问性
  • 基类中不同访问域的重载函数名不可进行访问声明
  • 基类与派生类中同名的重载函数名不可进行访问声明

重名成员

C++允许派生类成员与基类成员重名。

访问特点:

  1. 在派生类中直接访问重名成员将屏蔽基类的同名成员。
  2. 在派生类中使用基类的同名成员,可显式使用作用域符:类名::成员
  3. 使用派生类对象访问重名成员时默认屏蔽基类的重名成员
  4. 使用派生类对象访问基类的同名成员,可显式使用作用域符:类名::成员

使用指针进行访问的特性:

  1. 基类指针指向派生类对象,只能访问从基类继承的重名成员,只能调用基类版本的重名成员函数。
  2. 派生类指针必须经过类型转换才能指向基类对象

虚继承

间接基类:A继承B,B继承C,则C是A的间接基类

多次继承的间接基类的空间分配:如果一个类多次成为同一个类的间接基类,那么该派生类将生成多份该间接基类的数据成员

虚继承的目的:无论成为多少次间接基类,在派生类中使只生成一份数据成员

形式如下:

class B
{...};
class B1: virtual public B
{...};
class B2: virtual public B
{...};
class B_base: public B1, public B2
{...};

在上述代码中,B1与B2使用虚继承,B_base中的B数据成员只会被创建一份。

虚函数

虚函数定义:类的成员函数名字前冠以virtual进行修饰。

class A
{public:virtual void test();
}
void A::test()
{...}

虚函数的意义:使用基类指针,此指针指向不同的基类或派生类对象时,调用相应对象自己版本的成员函数。使用虚函数,统一数据接口,多个同一基类的派生类只要使用一个基类指针,就可以调用不同版本的同名成员函数。

基类指针的使用:可以使用基类指针指向派生类对象,但是此指针只能访问从基类继承的数据成员,调用与基类重名的函数时,只会调用基类的版本。

虚函数的本质:基类指针指向不同派生类对象,调用同名成员函数会自动转化this指针的指向。使用动态联编的方法,即在程序运行时,确定调用哪个版本的同名成员函数。

  • 虚函数使用特性:

    • 重载特性:要求函数名、返回类型、参数个数、参数类型和顺序完全相同。

    • 定义特性:

      • 无论经过多少层次派生类的重载,都具有动态调用的虚特性

      • 必须是类的成员函数,不能是全局函数或静态成员函数

      • 不可将友元说明为虚函数,可以是另一个类的友元

      • 析构函数可以是虚函数,构造函数不可以是虚函数

可见,一般只需要基类定义虚函数,派生类按照要求重载即可。

虚析构函数

使用基类指针指向派生类对象时(或者使用基类指针new派生类对象),此时对此基类指针使用delete,只会调用基类的析构函数而不会调用该派生类的析构函数。

为此,需要使用虚析构函数,使得使用delete时调用派生类的析构函数。

结论:将一个基类的析构函数定义为虚函数是有意义的,没有其余的坏处。

纯虚函数

基类中赋值为0的虚函数,没有具体实现,要求所有派生类实现自己的版本。

virtual 类型 函数名(参数表) = 0;
// 或者
virtual 类型 函数名(参数表) const = 0;
抽象类

至少具有一个纯虚函数的类称为抽象类;继承了抽象类并对其内纯虚函数做了具体实现的派生类称为具体类。

抽象类的使用限制:

  • 只能用于其他类的基类
  • 不能建立对象
  • 不能用于参数类型,但可以说明抽象类的引用参数
  • 不能用于函数返回类型

抽象类的使用意义:

定义抽象类后,进行继承得到具体类,然后使用一个抽象类指针通过指向不同的具体类对象,调用不同版本的虚函数。或者定义一个函数使用抽象类的引用参数,通过传入不同派生类对象,在其中调用其纯虚函数。实现了统一的数据接口。

抽象类使用参考代码:

class base
{public:virtual void show() const = 0;
}
class B1:public base
{public:void show() const{cout<<"B1"<<endl;}
}
class B2:public base
{public:void show() const{cout<<"B2"<<endl;}
}
void show(base &b)
{b.show();
}
int main()
{B1 b1;B2 b2;show(b1);show(b2);
}

编程手札:C++快速笔记相关推荐

  1. [.NET] 《Effective C#》快速笔记 - C# 中的动态编程

    <Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...

  2. python开发视频大全_2019年python开发编程21天快速入门视频教程+书籍大全和面试大礼包...

    极力推荐这套python资料,不是那种庞大的复杂的难以入门的课程,这套课程十分简单.其中一套21天入门python的课让你以最快的速度入门,加上另一套python资料包(其中包括了几十本python学 ...

  3. [.NET] 《Effective C#》快速笔记(一)- C# 语言习惯

    <Effective C#>快速笔记(一)- C# 语言习惯 目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 ...

  4. 《Effective C#》快速笔记(三)- 使用 C# 表达设计

    目录 二十一.限制类型的可见性 二十二.通过定义并实现接口替代继承 二十三.理解接口方法和虚方法的区别 二十四.用委托实现回调 二十五.用事件模式实现通知 二十六.避免返回对内部类对象的引用 二十七. ...

  5. 《Java编程思想》读书笔记

    前言:三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第十七章到第十八章的内容,这一次 ...

  6. [转]《Python编程金典》读书笔记

    <Python编程金典>读书笔记 原文: http://man.chinaunix.net/develop/python/python_howto/python_howto_program ...

  7. 《Python编程金典》读书笔记

    << Back to man.ChinaUnix.net <Python编程金典>读书笔记 整理:Jims of 肥肥世家 <yjnet@21cn.com> 第一次 ...

  8. 《Java 并发编程实战》--读书笔记

    Java 并发编程实战 注: 极客时间<Java 并发编程实战>–读书笔记 GitHub:https://github.com/ByrsH/Reading-notes/blob/maste ...

  9. 《Java并发编程实践》学习笔记之一:基础知识

    <Java并发编程实践>学习笔记之一:基础知识 1.程序与进程 1.1 程序与进程的概念 (1)程序:一组有序的静态指令,是一种静态概念:  (2)进程:是一种活动,它是由一个动作序列组成 ...

最新文章

  1. linux下如何查询jdk的安装路径
  2. 实战—用户价值模型搭建
  3. 飞畅 Profibus总线光纤中继器产品介绍
  4. Atitit. 提升软件开发效率and 开发质量---java 实现dsl 4gl 的本质and 精髓 O725
  5. spring 配置文件模板
  6. Linux 串口编程四 串口设备程序开发
  7. 永远要跟比你更成功的人在一起
  8. 基于RStudio 实现数据可视化之二
  9. Web端打开文件选择和保存对话框
  10. petalinux笔记
  11. lwj_C#_泛型使用
  12. Python压缩文件夹
  13. springboot集成openoffice实现office转PDF在线预览
  14. 关于示波器探头的输入容抗问题解决
  15. html 苹果 地图,pdrLocationIos0508.html
  16. UI设计色彩趋势总结
  17. C语言程序设计培训视频教程
  18. 评论:“哭不起”的王君为何还流泪
  19. 微信开发者工具git 删除项目
  20. Epoll之ET、LT模式

热门文章

  1. 【调剂】广西师范大学计算机与信息工程学院 陈明教授课题组招收计算机与自动化方向调剂生3名...
  2. 《Unity》如何在任意一条线段中心上绘制一个三角形。
  3. 判断一个字符串是否为另外一个字符串旋转之后的字符串。 例如:给定s1 =AABCD和s2 = BCDAA,返回1,给定s1=abcd和s2=ACBD,返回0. // // AABC
  4. 使用腾讯云实现发送短信验证码登录的后端实现
  5. IB纪录:At the heard of the image
  6. 人人都是产品经理-序
  7. 比布拉奇数列c语言,斐波那契数列与贝祖数的估计介绍
  8. uniapp里自定义底部导航demo效果(整理)
  9. 80 8080 443
  10. 杨智凯推荐系统_2018年英特尔杯大学生电子设计竞赛嵌入式系统专题邀请赛评.PDF...