C++知识框架梳理

书接上文(C++知识框架梳理第一部分)(链接跳转:https://blog.csdn.net/weixin_74804051/article/details/129104782

二:继承

1.派生继承

a.什么是派生、继承:

答:举例说明,假如我们有个学生student 类,student又可以细分为本科生和研究生。本科生和研究生也是学生,是学生的子类。学生是父类,也叫作基类或者超类。所谓派生,是相对于父类而言的,父类派生子类;所谓继承,是相对于子类而言的,子类继承父类。

派生的写法:

//从学生派生出本科生
class undergraduate :public student//本科生类定义,冒号后面表示从student类共有派生而来
{
public :
    stringcource;//这行表示在学生的父类基础上,定义了一个新的公开的字符串属性course。比如本科生的物理课程
}
//从学生派生出研究生
class postgraduate :public student
{
public:
    stringresearch;//这行表示研究生又新增了research 研究方向的字符串属性
}

对比两个类

发现都没有写父类的两个属性name age,因为根本不用写,子类会自动继承父类的共有的属性和方法。同样,构造函数也可以被继承;派生类也是可以有自己的属性和方法的。这是很重要的一点;子类的name和age也是有值的,因为子类自动继承了父类的构造函数,所以name和age被自动赋初始值了。

b.类在不同情况下的继承

c.protect

除了public和private,还有一个和他们平级的关键字:protect

在没有派生继承的情况下,protect和private的效果是完全一样的。

在研究生类定义中:

//从学生派生出研究生
class postgraduate :public student
{
public:
    stringresearch;//这行表示研究生又新增了research 研究方向的字符串属性
}

public表示共有继承,只继承student的共有部分,并且student中的共有部分也会作为研究生类的共有部分(student中的age和name)。研究生是无法继承也是无法访问student类的私有部分的。

将父类student类定义中的private替换成protect

这对student本身并无影响,并无变化。

但当在进行子类派生出研究生类的时候:class postgraduate:public student {…}的时候,除了父类中的public被继承了,父类中的protect也被研究生继承了。student中的protect内容被继承到了postgraduate的protect中。

d.公有继承总结:

父类student,public内容A,private内容B,子类postgraduate共有继承,则只有public内容A

父类student,public内容A,protect内容B,子类postgraduate公有继承,则只有public内容A+protect内容B

d.私有继承和保护继承总结:

class postgraduate:public student{...}中的public替换成private和protect

父类public内容A,private内容B,子类私有继承,则子类只有内容A,且内容A为private

父类public内容A,protect内容B,子类保护继承,则子类有内容A、B且都为protect

在保密优先级上,private最为私密,protect其次,public最公开。private里面的内容是无论如何都不会被继承的。

e.子类的构造函数:

子类也是可以有自己的构造函数的。子类没有构造函数,系统会调用父类student的构造函数,创建子类对象时,父类构造函数将被调用。

子类函数构造示例:

//子类构造函数示例
class postgraduate:public student
{public:
    string research;
    postgraduate();//无参数构造函数声明
    postgraduate(int a,string b,string c);//带参数的构造函数声明
}
//无参数构造函数定义
postgraduate::postgraduate()
{ research="asic design";}
//带参数的构造函数定义
postgraduate::postgraduate(int a,string b,string c):student(a,b)//带参数的子类构造函数,定义和声明长的不一样,后面多了东西。
{research=c;}
//主函数
postgraduate bb;
postgraduare cc(25,"李四","ASIC design");

无参数的子类构造函数过程中:

创建子类对象bb后,系统自动运行父类student构造函数,对age和name进行赋值。随后运行子类postgraduate的构造函数,对bb对象进行拓展,增加research内容。子类是不可以继承父类的构造函数的,只能调用。

带参数的子类构造函数过程中:

程序会先调用父类student构造函数,把25和李四两个值传入父类student 带参数的构造函数。随后把参数c=Asic design 传给bb自己的research属性,这样就实现了对研究生对象的全动态的初始化赋值。

三:多态

1.多态的初步

a.方法真的是专属于某个类的吗?

在刚开始了解类的时候,我们可能会以为方法是专属与某个类的,例如说加法+是属于整树类的,例如3+4,是不可以用于字符串类的,我们不可以直接使用+来让两个字符串相加。

但是,在比较新的编程语言中,例如Python和ruby是可以执行两个字符串的加法的,是将两个字符串给直接拼接起来。

多态的思想:不同类的对象也可以用相同的方法,相同指的是相同的方法名字,但是具体干了什么,是不一样的。

例如:a,b为数字时,“+”执行传统意义的加法

a,b 为字符串时,“+”执行字符串拼接,系统将根据当前情况智能选择采用哪种方法。

以上的说法是不太严谨的,是大致的意思,但是在Python等新兴语言中是正确无误的,对于c++来说,上面的说明并没有很严谨。

b.C++实现相同的函数名执行不同的内容的三种方法

在C++中,因为C++较为古板,若要实现相同的函数名执行不同的内容,有以下三种方法:

重载;隐藏;覆盖(override,又叫重写,这个才是C++的多态)

c.重载:

Python a+b 这个例子中,C++中看上去更接近重载;重载两个函数的参数格式必须是不一样的;隐藏和覆盖的同名函数的参数可以完全一样;重载不依赖于面向对象,依赖编译器。

d.隐藏:

在父类student和子类postgraduate 中都定义一个函数student() 输入参数格式相同不同都可以。

下面是一个例子:

class student 
{
public :
    void study (bool a) {cout<< "好好学习";}
}
class postgraduate
{
public:
    void study (int b) {cout<<"天天向上";}
}
//主函数
postgraduate bb;
student aa;
bb.study (2);  //打印出天天向上
aa.study (true);//打印出好好学习
bb.study(true);   出错,研究生对象,但参数为bool,本来应该重载父类的study方法,但因为父类方法被隐藏,系统找不到对应方法,这就是隐藏和重载的区别。子类的找不到父类的同名函数,父类的会被隐藏。
e.多态
类的指针

要想了解真正的多态,必须先讲指针。

我们在实际的程序中,会大量的使用类指针。

不考虑继承,类指针域结构体指针类似;

student *P;//新建一个student类指针
student aa;//新建aa对象
p=&aa;//p指针指向aa对象
p->name;//这个就和aa.name 一样,返回aa的name的值
p->study();//相当于aa.study(),对aa执行成员函数

实际程序中使用更高级的写法:

student *P=new student (20,"张三");//这样就直接设置了一个变量指向了新建的student对象
delete p;//调用析构函数

把继承考虑进去,复杂一点

student *p1;
postgraduate *p2;
student aa;
postgraduate bb;
p1=&aa;//父类指针指向父类对象,可以
p2=&bb;//子类指针指向子类对象,可以
p1=&bb;//父类指针指向子类对象,可以
p2=&aa;//子类指针指向父类对象,不可以,报错

父类指针可以指向子类成员,反过来则不行

因为研究生一定是学生,反之则不一定

但是,虽然父指针指向了postgraduate,但不能调用子类的属性和方法,仍然只能用父类的方法。

真正的多函数与虚函数

分别在student,undergraduate,postgraduate 建一个方法,都叫study,但每个study学习内容是不一样的。同时在所有的子类父类study声明前面加上关键字,virtual ,表名这是一个虚函数

class student
{
public:
    virtual void study();
}
void student::study(){cout<<"好好学习";}
class postgraduate:public student
{
public:
    virtual void study();
}
void postgraduate::study(){cout<<"芯片设计";}
class undergraduate:public student
{
public:
    virtual void study();
}
void undergraduate::study(){cout<<"大学物理";}

在三个类中都设置了同名虚函数,并且他们的输入参数都是一样的,也就是没有参数,这和重载是不同的。

student aa;
postgraduate bb;
undergraduate cc;
student *P;
p=&aa;
p->study()://调用学生study方法
p=&bb;
p->study()://调用研究生study方法
p=&cc;
p->study()://调用本科生study方法
f.C++多态的核心:

答:就是只要在程序开始时设置一个父类指针,之后这个指针可以动态的指向不同的类,并且指针还可以动态的调用不同的类的方法,从而实现了不同数据类使用相同的方法。重载是编译时决定的,多态是运行时决定的。

2.纯虚函数与抽象类

a.抽象类:

学生是一个类,但是学生又分为研究生,本科生,小学生,高中生等等子类,单纯属于学生类而不属于任何一个子类的对象是不存在的。学生类不应该具有自己的对象,于是学生类被叫做抽象类。

设置抽象类依赖纯虚函数

class student
{
public :
student();
student(int a,string b);
virtual void study() =0;//声明study方法,注意前面加了virtual还有=0,表明这是纯虚函数。
}
//主函数
student aa;//报错,不允许创建抽象类对象
student *p;//可以创建抽象类指针
postgraduate bb;
p=&bb;
p->study()://通过多态调用子类的study方法

当设置了virtual void study()=0;后

student就是一个抽象类

study()函数只有声明,没有定义,其具体内容靠子类的多态来实现。

在创建了抽象类后,我们仍然可以创建一个抽象类的指针,但是不可以创建抽象类的对象了。

我们在使用了抽象类后,父类student仍然可以有自己的属性,但是不可以有自己的方法了。因为研究生,本科生,中小学生等子类都有自己的方法,所以具体的方法还是应该考子类的方法来进行实现。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值