C++

const 修饰符

1.const 作用与 #define 相似,但是它消除了 #define 的不安全性比如:
#define T1 a+a
#define T2 T1-T1
2.const 与指针组合可以归纳为 3 种类型;
(1) 指向常量的指针
3. 指向常量的指针
const char * name=“chen”;
name=“zhang”;
4. 常指针
char * const name=“chen”;
name[3]=‘a’;
5. 指向常量的常指针
const char * const name=“chen”;

内联函数

  • 原因:为了消除函数调用时的系统开销,以提高运行速度。
    inline int box(int i,int j,int k)
    int main()
    {
    int a,b,c,v;
    cin>>a>>b>>c;
    v=box(a,b,c);
    cout<<“a * b * c=”<<v<<endl;
    return 0;
    }
    inline int box(int i,int j,int k)
    {
    return i * j * k;
    }

带有默认参数的函数

  • 要求:在声明函数时,所有带有默认值的参数必须出现在不指定默认值参数的右边。
    错误:int fun (int i,int j=5,int k);
    正确:int fun (int i,int k,int j=5);
  • 要求:函数调用时,如果某一个参数省略,后面的参数只能省略采取默认值,不能赋予新的值。
    错误:special (,21.5);

函数的重载

  • 含义:当两个或两个以上的函数共有一个函数名时,称为函数的重载。
    例如:
    int square(int i)
    {
    return i * i;
    }
    long square(long l)
    {
    return l * l;
    }
    double square(double d)
    {
    return d * d;
    }
  • 注意:调用重载函数时,如果两个函数的参数和类型都相同,而只有返回值类型不同,则不允许重载。
    例如:
    int mul(int x,int y);
    double mul(int x,int y);
    不允许重载
  • 注意:函数的重载与带默认值的函数一起使用时,有可能引起二义性
    比如:
    void Drawcircle(int r=0,int x=0,int y=0);
    void Drawcircle(int r);
    当执行 Drawcircle (20);
    系统无法确定调用哪一个函数

作用域运算符 "::"

通常情况下,局部变量在作用域内具有较高的优先权,它将屏蔽全局变量。

  • 如果希望在局部变量的作用域内使用同名的全局变量,可以在这个变量前加上 "::","::" 称为:作用域运算符
    例如:
    int avar;
    int main()
    {
    int avar;
    avar=25; // 给局部变量赋值 25
    ::avar=10; // 给全局变量赋值
    cout<<“local avar=”<<avar<<endl;
    cout<<“global avar =”<<::avar<<endl;
    return 0;
    }
    输出:
    local avar =25
    global avar =10

运算符 new 和 delete

  • new
    int * p;
    p=new int;
  • delete
    delete p;
  • 注意:
  1. 使用 new 为多维数组分配空间时,必须提供所有维的大小
    如:int * pi =new int [2][3][4];
  2. new 可在为简单变量分配内存的同时,进行初始化。
    指针变量名 = new 类型(初值)
    int * p;
    p=new int(99);

引用

  1. 别名
    int i=5;
    int &j=i;
    注意:i 和 j 的地址一样,i 和 j 同时变化。
    不能建立 void 类型
    不能建立引用的数组
    不能建立引用的引用
  2. 引用作为函数参数
    例如:
    void swap(int &m,int &n)
    {
    int temp;
    temp=m;
    m=n;
    n=temp;
    }
    int main()
    {
    int a=5,b=10;
    swap(a,b);
    }
  3. 使用引用返回函数值

结构体与类

类是对象的抽象,对象是类的实例。

  • 注意:私有成员 (数据成员和成员函数) 只能被类内的成员函数访问,不能被类外的对象访;公有成员都可以被访问
  • 注意:在实际应用中,一般把需要保护的数据设置为私有的,把它隐蔽起来,把成员函数设置为公有的,作为类与外界的接口。

成员函数的定义

静态成员

  • 静态数据成员
    1. 当我们想要用在__同一个类中 (学生类) 任何一个对象__共享__一个数据 (这个数据可以累计前面对象的数据情况,不会随着定义下一个对象就刷新)(平均分、学生总人数、总成绩…),就应该将这个数据定义为静态数据成员
    2. 虽然将数据成员定义为全局变量也可以达到同样的目的,但是全局变量具有__不安全性
    破坏面对象程序的封装性__特点
    3. 格式:
    static 数据成员 数据成员名
    4. 静态数据成员初始化应该在类外单独进行,而且在定义对象之前进行
    5. 初始化格式:
    数据类型 类名::静态数据成员名 = 初始值
    注意:数据成员名之前不要加 static
    6. 静态数据成员属于类,而__普通数据成员属于对象
    ,因此在访问静态数据成员时,__可以 (并非只能)__用类名访问,格式:
    类名::静态数据成员名
    7. 用对象访问静态数据成员格式:
    对象名。静态数据成员名
    8. 私有静态数据成员不能在类外被访问,应该通过公有成员函数访问
  • 静态数据成员函数
    1. 静态成员函数属于整个类,是该类所有对象共享的成员函数
    2. 格式:
    static 返回类型 静态成员函数名 (参数表);
    3. 调用格式:
    (规范) 类名::静态成员函数名 (实参表)
    4. 使用静态成员函数其中一个原因是,可以用它在建立任何对象之前调用静态成员函数,以处理静态数据成员。原因:在调用静态成员函数中的静态成员已经被初始化,可以用来调用以及运算
    5. 编译系统将静态成员函数限定为内部连接,所以其他文件中的同名函数不会与该函数发生冲突
    6. 静态成员函数与非静态成员函数的区别为:非静态成员函数有 this 指针,而静态成员函数没有
    7. 一般来说__静态成员函数不能访问类中的非静态成员__,若要访问只能通过 (对象名、对象指针、对象引用)

友元

  • 友元函数
    1. 类中的私有成员是受保护的,只有类中的成员函数能访问 (一般调用构造函数), 此时友元函数便可以作为一个小口子用来访问其中的私有成员
    2. 既可以是不属于类的非成员函数 (普通函数),也可以是另一个类的成员函数
    3. 友元函数可以定义在类的内部,也可以定义在类的外部
    4. 定义友元函数需要在函数名之前加上关键字 friend
    5. 由于友元函数权限范围很大,不可具体划分为某一类成员函数,属于一种特殊的函数,因此在外部定义时,按照普通函数的定义即可
    6. 友元函数时特殊的函数,不属于类的成员,所以它不能直接访问对象的数据成员,也不可以通过 this 指针访问,必须通过 (对象指针或者对象的引用) 来实现
    7. 使用友元函数可以提高运行效率
    类中的私有成员不可以被类外部访问,必须构造函数进行调用,这时候,如果大量需要访问私有成员,就会不停的调用函数进行访问,浪费时间,降低运行效率
  • 将成员函数声明为友元函数
    1. 当有两个类时,我想要__两个类中的数据有共同使用的部分__(在一个类中调用另一个类中的私有数据成员),就可以在其中一个类 A 中将函数声明为它的成员函数,在另一个类 B 中声明为 A 中的成员函数为 B 的友元函数,其中 A 中的私有数据成员可以直接 cout,B 中要访问私有数据成员就要用 (对象指针或者对象的引用) 来调用私有数据成员来 cout
    2. 注意类的引用声明以及定义
  • 友元类
    1. 格式:
    friend 类名;
    2. 当类 Y 被说明为类 X 的友元时,类 Y 中的所有成员函数都可以访问 X 中的__所有__数据成员

类的组合

class X
{
类名 1 对象成员 1;
类名 2 对象成员 2;
.
.
.
类名 n 对象成员 n;
};
类 X 的构造函数定义为:
X::X (形参表 0):对象成员 1(形参表 1),对象成员 2(形参表 2),…
{
// 类 X 的函数构造体
}

常类型

常类型是指使用类型修饰符 const 说明的类型,常类型的变量或者对象成员的值在程序运行期间是不可以改变的

  • 常引用
    例如:
    int a=5;
    const int &b=a;
    b 是一个常引用,这时候 b 的 值可以随 a 的值而改变 (可以改变 a 的值),而不可以改变 b 的值
  • 常对象
    常对象的数据成员值在整个生存期内不能被改变
    格式:
    类名 const 对象名 [(参数表)];
    或者
    const 类名 对象名 [(参数表)];
    常对象不能调用普通成员函数
    在定义对象时必须进行初始化,而且不能被更新
  • 常对象成员
    1. 常数据成员
    使用 const 说明的数据成员称为常数据成员,如果一个类中说明了常数据成员,那么构造函数就只能通过成员初始化列表对该数据成员进行初始化,并且其他任何函数都不能对该成员赋值
  • 常成员函数
    在类中使用关键字 const 说明的成员函数为常成员函数
    格式:
    类型说明符 函数名 (参数表) const;
    常成员函数可以访问常数据成员,也可以访问普通数据成员。常数据成员可以被常成员函数访问也可以被普通成员函数访问

派生类的概念

当两个类有很多相同的地方,为了提高代码的可重用性,可以引入继承

  • 派生类的声明
    class 派生类名:[继承方式] 基类名
    {派生类新增的数据成员和成员函数};
    继承方式可以为:private (私有继承)、protected (保护继承)、public (公有继承)
    如果没有给出继承方式,系统默认为私有继承
  • 派生类的构成
    派生类把基类的全部成员 (除构造函数和析构函数之外) 接收过来
  • 基类成员在派生类中的访问属性
    1. 基类中的私有成员
    无论哪种继承方式,基类中的私有成员不允许派生类继承
    2. 基类中的公有成员
    当类中的成员以什么方式继承时,基类中的所有公有成员就以什么成员的方式出现
    3. 基类中的保护成员
    当类中的成员以公有或保护方式继承时,基类中的所有保护成员就以保护成员的方式出现
    当类中的成员为私有继承时,基类中的所有保护成员就以私有成员的方式继承
  • 派生类对基类成员的访问属性
基类中的成员 在公有派生类 在私有派生类 在保护派生类
私有成员 不可直接访问 不可直接访问 不可直接访问
公有成员 公有 私有 保护
保护成员 保护 私有 保护
  • 派生类对基类成员的访问规则
    类的继承方式有 public (公有继承)、protected (保护继承)、private (私有继承)
    访问形式:内部访问、对象访问
  1. 私有继承访问规则
基类中的成员 私有成员 公有成员 保护成员
内部访问 不可访问 可访问 可访问
对象访问 不可访问 不可访问 不可访问
  1. 公有继承访问规则
基类中的成员 私有成员 公有成员 保护成员
内部访问 不可访问 可访问 可访问
对象访问 不可访问 可访问 不可访问
  1. 保护继承访问规则
基类中的成员 私有成员 公有成员 保护成员
内部访问 不可访问 可访问 可访问
对象访问 不可访问 不可访问 不可访问

派生类的构造函数和析构函数

  • 派生类构造函数和析构函数的执行顺序
    构造函数:
    1. 基类构造函数
    2. 派送类构造函数
    析构函数:
    1. 派生类析构函数
    2. 基类析构函数
  • 派生类构造函数和析构函数的构造规则
    派生类名 (参数总表):基类名 (参数表)
    {
    派生类新增数据成员初始化语句
    }
    注意:
    在类中声明派生类的构造函数时,不包括基类构造函数名及其参数表,只有在类外定义时才将它列出
  • 派生类的析构函数
    析构函数调用顺序与构造函数相反
  • 含有对象成员 (子对象) 的派生类的构造函数
    派生类名 (参数总表):基类名 (参数表 0),对象成员名 1 (参数表 1),…,对象成员名 n (参数表 n)
    {
    派生类新增成员的初始化语句
    }
    构造函数执行顺序如下:
  1. 调用基类
  2. 调用内嵌对象成员
  3. 派生类

基类成员在派生类中的访问属性的其他方法

  • 同名成员
    为了在派生类中使用基类的同名成员,必须在该成员名之前加上基类名和作用域标识符::(在派生类中使用基类同名函数)
    基类名::成员名
  • 访问声明

多重继承

  • 多重继承派生类的声明
    class 派生类名:继承方式 1 基类名 1,…,继承方式 n 基类名 n
    {
    派生类新增的数据成员和成员函数
    };
  • 多重继承派生类的构造函数与析构函数
    派生类名 (参数总表):基类名 1 (参数表 1), 基类名 2 (参数表 2),…, 基类名 n (参数表 n)
    {
    派生类新增成员的初始化语句
    }
    析构函数执行顺序与构造函数相反
  • 虚基类
    1. 如果一个类中有多个直接基类,并且这些基类又有共同的基类,为了避免同名函数不知道如何调用,产生了虚机类
    2. 语法形式:
    class 派生类名:virtual 继承方式 基类名
    {
    }
    3. 虚基类初始化
    (1) 所有直接间接的派生类都必须在构造函数初始化列表中列出对虚基类的构造和函数的调用,以初始化虚基类中定义的数据成员
    (2) 调用顺序为:
    虚基类
    非虚基类
    成员对象
    派生类
    (3) 对于多个虚基类或非虚基类,构造函数的执行顺序总是先左后右,自上而下
  • 基类与派生类对象之间的赋值兼容关系
    公有继承派生类对象既是基类对象又是派生类对象

多态性

  • 运算符重载
    运算符重载可以是类外定义的普通函数,也可以是类的成员函数或友元函数
    有时候我们需要将类中定义的几个对象的数据进行计算,但是由于类的对象不是基本数据类型,而是用户自定义的数据类型,所以导致不能进行计算,这时需要进行运算符重载来实现。
    1. 在类外定义的运算符重载函数
    类名 operator 运算符 (类名 对象 1,类名 对象 2…)
    {
    类名 新对象
    计算过程
    }
    C++ 绝大运算符可以重载,以下运算符不能重载
    。成员访问运算符
    . * 成员指针访问运算符
    ::作用域运算符
    sizeof 长度运算符
    ?:条件运算符
    不允许用户自己定义新的运算符
    2. 友元运算符重载函数
    在类中定义
    friend 函数类型 operator 运算符 (形参表)
    {
    函数体
    }
    在类外定义
    函数类型 operator 运算符 (形参表)
    {
    函数体
    }
    3. 成员运算符重载函数
    在类中定义
    函数类型 operator 运算符 (形参表)
    {
    函数体
    }
    声明:函数类型 operator 运算符 (形参表);
    在类外定义
    函数类型 ::operator 运算符 (形参表)
    {
    函数体
    }
  • 指针悬挂问题
    详见 CSDN 收藏夹

虚函数

访问量 访客