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

编程手札: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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值