C++学习笔记三

1、派生类要想覆盖(重写)基类中的虚函数,那么其提供的新定义,其函数原型必须完全符合基类所声明的函数原型,包括:参数列表、返回类型、常量性(const-ness)。
解释:
基类中的虚函数被声明为const函数(就是在参数列表括号的右边加上const关键字),那么派生类中对应的虚函数也要写成const函数,另外返回类型一般情况下绝对要一致,比如基类中为const char*,那么派生类中也要是const char*,不能省略const,参数列表绝对绝对要一致。
上面说到了一个一般情况下,那么那个特殊情况是什么呢?
当基类的虚函数返回基类的指针或引用时,返回类型不必完全吻合。
比如有类A和类B(其中类B是类A的子类)
virtual A* clone() = 0;
B* clone(){return new B(*this)} //其中调用了拷贝构造函数

2、有两种情况,虚函数机制不能实现多态:(1)基类的constructor和destructor内 (2)当我们使用的是基类的对象,而非基类对象的pointer或reference时。
解释:
(1):(联系笔记一)
若在基类的构造函数中调用了虚函数,此时子类对象都还没有创建好,要是调用的是子类对象的虚函数那么它便可能访问尚未被初始化的子类对象的成员变量,所以说基类的constructor中不会出现所谓的多态!
若在基类的析构函数中调用了虚函数,此时子类对象已经析构完毕,要是调用的是子类对象的虚函数那么它便可能访问已析构完毕的子类对象的成员变量,这显然是会出错的,所以说基类的destructor中不会出现所谓的多态!
不会出现所谓的多态意思就是调用的虚函数来自所作用对象对应的类
(2):
子类对象往往是基类对象的扩展,当用基类对象调用虚函数时,若要实现执行子类中的虚函数,那么可能子类中虚函数需要特定的子类中的成员变量,而这些成员变量恰恰是基类对象没有的,在所谓的类型转换过程中子类对象的那些成员变量就被切割掉了,,只保留了基类对象所本有的那一部分成员变量,那么基类对象所调用的虚函数只能是自己的虚函数,不能是子类的虚函数,所以说我们使用的是基类的对象,而非基类对象的pointer或reference时,不会出现所谓的多态。

3、运行时类型识别
需要把这个父类子类公共函数被声明为虚函数,使父类就变为抽象基类,这时候就能用到运行时类型识别(Run-Time Type Identification RTTI)来知晓该指针指向的具体类型,而不是在程序编译时仅从指针声明语句得出该指针的类型,进而完成函数的动态绑定。

4、在c++程序中如果想要调用c中的库函数,比如C中stdio.h头文件中的printf()函数,stdlib.h头文件中的exit()函数,可以直接像c语言中那样写,比如#include<stdio.h>,但更推荐写成#include< cstdio>,类似的还有#include< cstdlib>,#include< cstring>等。

5、通过基类的pointer或reference,不能通过多态访问子类中的的非虚函数和成员变量,因为基类指针表示的范围没有子类指针的大,只能囊括自己独有的部分以及与子类指针共有的部分。

#include <iostream>
using namespace std;


class Animal {
public:
    
    virtual ~Animal() = default;
    virtual void specie(){cout<<"A"<<endl;}
    public:
    int i;
};

class Bee : public Animal {
    
    virtual void specie(){cout<<"B"<<endl;}
    void fly(){cout<<"fly"<<endl;}
    public:
    int j;
};

int main()
{
    Animal *A1 = new Bee;
    A1->specie();//成功
    A1->i=0;//成功!
    //A1->fly();//编译报错:class "Animal" has no member "fly"
    //A1->j=0;//编译报错:class "Animal" has no member "j"
    return 0;
}

在这里插入图片描述

6、通过使用所谓的::(类作用域解析运算符),类名::函数名可以调用类中的静态函数,为什么没说非静态函数呢,因为静态函数中一定不能访问任何的non-static-member,而非静态函数可以,用类名加::来调用非静态函数具体作用的是哪个类的对象呢?不得而知,如果你发现可以调用的话,那你就得好好看看你这个非静态函数是不是可以声明为静态函数了。
在这里插入图片描述

7、在一个类中的各个函数定义中,不管这个函数定义写在类主体内还是类主体外,这个函数都可以直接调用类中的其它函数,不用在其它函数的调用前加特定的对象!类的成员函数是具有访问类私有成员的权限的,也就是最高权限(都能访问)java中也是一样

8、一般类的定义写在头文件中,类中内联函数的定义也是一样,联系笔记二中的6,其余成员函数的定义写在和通常和类名相同的.cpp文件中,注意格式:返回值类型 类名 :: 函数名(参数列表){函数体},另外静态成员(包括data member和member function)的定义也写在.cpp文件中,只有声明为const static 的静态成员可以直接在类中给定其清楚的定义。联系笔记二中的12

9、类之间的公有继承,继承来的public和protected成员,不论在继承体系中的深度如何,都可被视为派生类自身拥有的成员,使用派生类时不必刻意区分“继承而来的成员”和“自身定义的成员”。两者使用完全透明。
也就是说,在子类中,你可以通过域解析运算符(::)成员名(成员函数名/成员变量名)调用“继承而来的成员函数和成员变量”,“自身定义的成员”可以直接访问,无需域解析运算符。联系6中图
在这里插入图片描述
上图最后一行空白处写的对象是,当前对象或该函数中定义了的派生类对象
另外可以看出,上图都是说可以被什么函数访问;第二大点的其他函数(想想main()函数)

在这里插入图片描述
在这里插入图片描述

10、派生类对象由两部分组成:一是基类构成的子对象(subobject),由基类的non-static data member——如果有的话——组成,二是派生类的部分(由派生类的non-static data member组成)。
派生类的基类子对象:
概念,在派生类的实例化的过程中,会先调用基类的构造函数,再调用派生类自身的构造函数,派生类对象中其实含有多个子对象,由基类constructor初始化的“基类子对象”,以及由派生类constructor初始化的“派生类子对象”。

11、抽象基类无法实例化(无法为它定义任何对象),但是它可以有自己的构造函数,它扮演的角色是每个派生类对象的子对象。所以说基类的constructor要声明为protected而不能是public。

12、reference永远无法代表空对象(null object),pointer却可以为null,所以说当一个构造函数中参数有reference的时候(成员变量有reference),就需要显式声明构造函数。

13、c++中指向类成员函数的指针

  • 定义指向成员函数的指针变量的形式 : 成员函数返回类型 (类名∷*指针变量名)(参数列表)
  • 成员函数指针变量值的形式 : &类名∷成员函数名;(记住这里要用取地址运算符哦)
  • 成员函数指针变量使用形式 : (对象.*指针变量名)(实参);或者(指向类对象的指针->*指针变量名)(实参);

14、
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
动态数组(vector),双向队列(deque),双向链表(list)
set指集合
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结尾:如有任何错误的地方欢迎指正

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菩提one

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值