Chacha学码日志 / No.3 C++知识点辨析(类&对象&数据共享与保护)

356 阅读7分钟

关于本篇

  • 用于每周知识复查 & 要点整理
  • 整理学习中产生困惑的点 & 易混淆的概念
  • 适合零基础小白👀巩固基础+期末考前突击
  • 不适合大佬进阶学习🧐

Chapter 4 类与对象

UML 图形标识

  • 数据成员:[访问控制属性] 名称 [重数] [:类型] [=默认值] [{约束特征}] 例:-hour: int +size:area=(100,100)

  • 函数成员:[访问控制属性] 名称 [(参数表)] [:返回类型] [{约束特征}] 例+setTime(newH:int=0, newM:int=0, newS:int=0):void

类 & 结构体 & 联合体 辨析

结构体联合体
基本语法ClassStructUnion
默认访问控制属性私有类型(private)公有类型(public)公有类型(public)
是否可有数据成员
是否可有函数成员

Chapter 5 数据的共享与保护

5.3 类的静态成员

静态数据成员静态函数成员
生存期静态生存期/
通过对象名访问
通过类名访问不可可(且一般习惯于通过类名调用)
UML语言下方添加下划线添加 <<static>> 构造型
访问方式类名::标识符
声明类的定义中:引用性声明;必须命名空间作用域某处进行类名限定定义性声明
  • 静态成员函数可以直接访问该类的静态数据和函数成员;
  • 访问非静态成员,必须通过对象名。

5.4 类的友元

友元关系提供了不同类或对象的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。

友元函数友元类
UML语言<<friend>><<friend>>

5.5 共享数据的保护

对既需要共享又需要防止改变的数据应该声明为常量

常对象

  • 数据成员值在对象的整个生存期间内不能被改变;
  • 必须进行初始化;
  • 不能被更新
  • 语法: const 类型说明符 对象名;
  • 不能通过常对象调用普通成员函数

用const修饰的类成员

  1. 常成员函数
  • 声明格式:类型说明符 函数名(参数表) const;
  • 在函数定义部分也要带const关键字
  • 通过常对象只能调用该类的常成员函数
  • 常成员函数调用期间,目的对象都被视为常对象
  • 不能更新目的对象的数据成员
  • 不能针对目的对象调用该类中没有const修饰的成员函数
  • const关键字可以用于对重载函数的区分
    void print();
    void print() const;
    
  • UML语言:<<const>>构造型
  • 对于无须改变对象状态的成员函数,都应当使用const
  1. 常数据成员
  • 任何函数都不能对该常数据成员赋值;
  • 构造函数对该数据成员进行初始化只能通过初始化列表

初始化&赋值

初始化赋值
定义一个变量或常量在定义一个变量或常量以后
为它指定初值使用赋值运算符修改它的值

静态数据成员 vs 常数据成员 vs 静态常数据成员

静态数据成员常数据成员静态常数据成员
基本语法staticconststactic const
访问方式类名::标识符
  • 类成员中 静态变量 和 常量 都应当在类定义之外加以定义
  • 静态常量如果具有整数类型or枚举类型————可以直接在类定义中为它指定常量值 Eg: static const int b =10;

常引用

  • 常引用所引用的对象不能被更新
  • 声明: const 类型说明符 &引用名;
  • const 引用只能绑定到普通对象,不能绑定到常对象
  • 常引用可以绑定到常对象
  • 对基本数据类型的常引用:不能为数据赋值;
  • 对类类型的常引用,不能修改它的数据成员 & 不能调用它的非 const 成员函数
  • 宜采用常引用的情景:
    1. 对于在函数中无须改变其值的参数,宜采用传值方式或传递常引用的方式(普通引用会使常对象无法被传入)
    2. 大对象传值耗时较多,建议传递常引用;
    3. 复制构造函数的参数宜采用常引用

5.6 多文件结构和编译预处理命令

C++源程序实例结构

  • 类的定义:类定义文件(*.h 文件)
  • 类的成员的实现:类实现文件(*.cpp 文件)
    1. 使用类名初始化静态数据成员
    2. 类的函数体
  • 主函数:类的使用文件(*.cpp 主函数文件)

声明的位置

声明的位置.png

外部变量与外部函数

  1. 外部变量
  • 声明:extern
  • 定义性声明 & 引用性声明
定义性声明引用性声明
在命名空间作用域中,不使用extern声明的变量
使用extern声明同时指定了初值
使用extern声明同时未指定了初值

p.s. 静态变量和静态函数即使使用extern声明,它们的使用范围仍然被限定在定义文件中

  1. 外部函数
  • 在所有类之外声明的函数(即非成员函数)都具有命名空间作用域
  • 若无特殊说明,均可在不同的编译环境内被调用(调用前需进行引用性声明(声明函数原型)即可)
  • 声明或定义时可进行extern修饰(无特殊效果)
  1. 将命名空间作用域的变量/函数限制在编译单元内
  • 旧有方式:static声明 static的3种用法
局部作用域类作用域命名空间作用域
作用声明具有静态生存期的对象声明类的静态成员(数据成员&函数成员)将命名空间作用域的变量/函数限制在编译单元内,不可被其他编译单元引用
生存周期静态生存期静态生存期静态生存期
  • 新的方式:namespace 匿名的命名空间

标准C++库 & 编译预处理

  • #来引导
  • 单独占用一行
  • 不用;结束
  • 可以出现在程序的任何位置
  1. #include
  • #include <文件名>:按标准方式搜索
  • #include "文件名":首先在当前目录搜索
  1. #define & #undef
  • C语言中用于定义符号常量
  • C++中建议在类型说明语句中用const进行修饰
  • #define定义空符号#define 标识符表示“‘标识符’已经被定义过”状态;配合条件编译指令一起使用
  1. 条件编译指令
  • 限定程序中某些内容在满足一定条件时才参与编译
  • 使同一程序在不同的编译条件下产生不同的目标代码
  • #if形式:
#if 常量表达式1
    程序段1 //当“常量表达式1”非零时编译本程序段
#elif 常量表达式2
    程序段2 //当“常量表达式1”为零 & “常量表达式2”非零时编译本程序段
#elif 常量表达式3
    程序段3 //当“常量表达式1”、“常量表达式2”为零 & “常量表达式3”非零时编译本程序段
#else
    程序段n+1 //其他情况下编译本程序段
#endif

#elfi#else#视情况可以省略:

#if 常量表达式1
    程序段1 //当“常量表达式1”非零时编译本程序段
#endif
  • #ifdef & #ifndef形式:
#ifdef 标识符
    程序段1 //如果“标识符”经#defined定义过,且未经undef删除,则编译程序段1
#else
    程序段2
#endif
#ifndef 标识符
    程序段1 //如果“标识符”未经#defined定义过,则编译程序段1
#else
    程序段2
#endif
  1. defined操作符
  • 是一个预处理操作符,不是指令
  • 不以#开头
  • 形式:defined(标识符)
  • 若“标识符”在此前经#define定义过,且未经#undefine删除——上述表达式==非0;否则==0;
  • 以下二者等价:
#ifndef MYHEAD_H
#define MYHEAD_H
    ...
#endif
#if!defined(MYHEAD_H)
#define MYHEAD_H
    ...
#endif
  • 在可能被重复包含的头文件中使用条件编译指令
  • 用一个唯一的标识符来标记某文件是否已参加过编译 - 如果已参加,说明该段程序被重复包含,编译时忽略重复部分

参考资料

  1. 《C++程序语言设计(第四版)》 郑莉 董渊 何江舟 编著