复试导师问题——程序语言(c\c++)

c++

为什么析构函数要用虚函数

https://www.cnblogs.com/howo/p/8531449.html

析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

虚函数:其实就是变成指针

	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}

虚析构和纯虚析构

问题

  • 多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

  • void test01()
    {
    Animal *animal = new Cat(“Tom”);
    animal->Speak();

      //通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏
      //怎么解决?给基类增加一个虚析构函数
      //虚析构函数就是用来解决通过父类指针释放子类对象
      delete animal;
    

    }

其他延伸

为什么无法调用子类代码

  • 因为之类pB是基类指针,虽然指向的是派生类,只能调用自己的函数,我们是无法通过基类指针调用到子类的成员函数的

多态满足条件

  • 有继承关系
  • 子类重写父类中的虚函数

子类继承父类后,当创建子类对象,也会调用父类的构造函数

构造函数在创建对象的时候调用,先调用父类,再子类,析构相反

(1)当父类的指针new一个子类的对象时,

父类析构不是虚析构,则delete的时候不调用子类的,只是调用父类的析构函数,如果是virtual的析构函数,则先子类之后父类

(2)当子类的指针new一个子类的对象时,构造析构都会调用父类

c/c++ 堆区程序员分配的内存,不释放,在程序结束时,系统一定会回收内存吗?

  • 程序结束是一定回收的,可以放心。内存溢出是如果你执行很久或者很大的程序,一直在申请不释放。或者比如说一个大项目,你写了一个模块,申请了一块内存不释放,别人调用你的模块调用了几千几万次,内存就溢出了。不过任何操作系统,程序结束了是肯定会回收的。

类中只要有一个纯虚函数就称为抽象类
//抽象类无法实例化对象
//子类必须重写父类中的纯虚函数,否则也属于抽象类

内存泄漏

  • 内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

深拷贝与浅拷贝

  • 浅拷贝:简单的赋值拷贝操作
  • 深拷贝:在堆区重新申请空间,进行拷贝操作
  • 如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题,如果不利用深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题

所谓拷贝就是平常意义的复制,至于深浅,就因为一个东西:指针拷贝的时候,如果有指针,那么也就是对指针的拷贝,指针怎么拷贝?指针本质也就是一个存储地址的整形,所以拷贝的时候,也就是把指针本身进行复制,这样就导致一个问题:本体与复制体的指针成员实际是一个值(地址值),那么他们会操作同一个地址的内存内容,在析构的时候,就出现问题了,本体或者复制体进行析构的时候,将指针成员kill了,即把指针成员对应的地址内容kill掉了,那么另外一个复制体或者本体的指针成员怎么办????野指针啊!

++i 与i++

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IwG7tfjh-1617287029349)(C:\Users\wangxiaobing\AppData\Roaming\Typora\typora-user-images\image-20210315185239494.png)]

全局变量和局部变量在内存中是否有区别?如果有是什么区别?

  • .生存周期不同 全局变量:全局区(静态区)(static):全局变量和静态变量是存储在一起的,初始化过的全局变量和静态变量在同一块区域,未初始化的全局变量和静态变量存放在一块相邻的区域内。此区域由系统在程序结束后释放 局部变量: 放在堆栈中。由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈
  • 作用范围不同 全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。 局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回

引用与指针有什么区别

  • 指针和引用都是地址的概念,指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。程序为指针变量分配内存区域,而不为引用分配内存区域。
  • 引用在定义时就被初始化,之后无法改变;指针可以发生改变。 即引用的对象不能改变,指针的对象可以改变。
  • 没有空引用,但有空指针。这使得使用引用的代码效率比使用指针的更高。因为在使用引用之前不需要测试它的合法性。相反,指针则应该总是被测试,防止其为空。
  • 对引用使用“sizeof”得到的是变量的大小,对指针使用“sizeof”得到的是变量的地址的大小。
  • 理论上指针的级数没有限制,但引用只有一级。即不存在引用的引用,但可以有指针的指针。
    int **p //合法
    int &&p //非法
  • ++引用与++指针的效果不一样。
    例如就++操作而言,对引用的操作直接反应到所指向的对象,而不是改变指向;而对指针的操作,会使指针指向下一个对象,而不是改变所指对象的内容。

面向过程面向对象

  • 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
  • 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
  • 面向过程就是一个问题被解决的自上而下的步骤实现;面向对象就是将解决问题的一些动作封装起来,赋予给一个对象,这个对象有解决的方法和一定的工作流程。

举例 :五子棋

  • 面向过程的设计思路就是首先分析问题的步骤:
    1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。
  • 而面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为:1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。

举例:洗衣服

  • 面向过程:
    将衣服丢进盆里→放洗衣液→放水→洗衣服→倒掉脏水→再放水→再清洗→拧干衣服→晾晒
  • 面向对象:
    把衣服放进洗衣机→放洗衣液→(洗衣机.放水()→洗衣机.洗衣服()→洗衣机.倒掉脏水()→洗衣机.再放水()→洗衣机.再清洗()→洗衣机.拧干衣服())→晒衣服

优缺点
面向过程

  • 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、
    Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
  • 缺点:没有面向对象易维护、易复用、易扩展

面向对象

  • 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护
  • 缺点:性能比面向过程低

Union

https://www.runoob.com/cprogramming/c-unions.html

#include <stdio.h>
#include <string.h>
 
union Data
{
   int i;
   float f;
   char  str[20];
};
 
int main( )
{
   union Data data;        
 
   data.i = 10;
   data.f = 220.5;
   strcpy( data.str, "C Programming");
 
   printf( "data.i : %d\n", data.i);
   printf( "data.f : %f\n", data.f);
   printf( "data.str : %s\n", data.str);
 
   return 0;
}

data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming

在这里,我们可以看到共用体的 if 成员的值有损坏,因为最后赋给变量的值占用了内存位置,这也是 str 成员能够完好输出的原因。

const修饰成员函数

常函数:

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数

常数据成员

  • 常数据成员必须进行初始化,并且不能被更新
  • 常数据成员只能通过构造函数的参数初始化表对常数据成员进行初始化
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王蒟蒻

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

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

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

打赏作者

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

抵扣说明:

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

余额充值