C++ 编程基础

STL 库描述

STL 库包括:容器、算法以及融合两者的迭代器。

容器分为顺序容器和关联容器。顺序容器比如 vector 是一个动态分配存储空间的容器。区别于 C++ 中的 arrayarray 分配的空间是静态的,分配之后不能被改变,而 vector 会自动重分配(扩展)空间。

内存中堆和栈的区别

  • 栈内存:由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈,都是先进后出。栈使用的是一级缓存,他们通常都是被调用时处于存储空间中,调用完毕立即释放**。
  • 堆内存:一般由程序员分配释放,若程序员不释放,程序结束时可能由 OS 回收。堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。

堆栈溢出一般是由什么原因导致的?

没有垃圾回收资源。

sizeof 的作用

sizeof 运算符返回一条表达式或一个类型名字所占的字节数,其满足右结合规律。

C++ 面向对象特点

数据抽象、继承和动态绑定。

多态的理解

  • 同一函数作用于不同的对象,会对应不同的实现,从而产生不同的执行结果。在运行时,可以通过指向基类的指针或引用,来调用实现派生类中的方法。
  • C++ 的多态性具体体现在运行和编译两个方面:在程序运行时的多态性通过继承和虚函数来体现;在程序编译时多态性体现在函数和运算符的重载上;

虚函数的理解

Python 不同,在 C++ 中,基类将类型相关的函数与派生类不做改变直接继承的函数区分对待。对于某些函数,基类希望它的派生类各自定义适合自身的版本,此使基类就会将这些函数声明成虚函数。同时,派生类内部必须在其内部对所有重新定义的虚函数进行声明。(参考 C++ Primer p526 页)

派生类必须使用类派生列表(class derivation list)明确指出它是从哪个(哪些)基类继承而来。派生的形式是:首先一个冒号,后面紧跟以逗号分隔的基类列表,其中每个基类前面可以有访问说明符。

class Student: public People{
    string names;
    virtual  double get_gpa (vector<float> scores);
}

动态绑定的理解

在 C++ 语言中,,当我们使用基类的引用(或指针)调用一个虚函数时,将发生动态绑定,即函数运行的版本由实参决定,运行时自动选择函数的版本。

C++构造函数初始化时什么时候只能用初始化列表?

如果类成员是 const、引用。或者属于某种未提供默认构造函数的类类型时,我们必须通过构造函数初始值列表为这些成员提供初始值。(参考 C++ Primer p259)

C++ 构造函数和析构函数的初始化顺序

本回答参考C++ 构造函数初始化顺序, C++奇奇怪怪的题目之构造析构顺序

多个基类的派生类(多继承) 的构造函数初始化按照如下顺序进行:

  1. 先执行虚拟继承的父类的构造函数;
  2. 然后从左到右执行普通继承的父类的构造函数;
  3. 接着按照定义的顺序执行数据成员的初始化;
  4. 最后调用类自身的构造函数;

析构函数就无脑的将构造函数顺序反转即可。多继承形式下的构造函数和单继承形式基本相同,只是要在派生类的构造函数中调用多个基类的构造函数。

实例代码如下:


#include <iostream>
 
using namespace std;
 
class OBJ1
{
public:
    OBJ1() { cout << "OBJ1" << endl; }
    ~OBJ1() { cout << "OBJ1 destory" << endl;}
};
 
class OBJ2
{
public:
    OBJ2() { cout << "OBJ2\n"; }
    ~OBJ2(){cout << "OBJ2 destory" <<endl;}
};
 
class Base1
{
public:
    Base1() { cout << "Base1" << endl; }
    ~Base1() { cout << "Base1 destory" << endl; }
};
 
class Base2
{
public:
    Base2() { cout << "Base2" << endl; }
    ~Base2() { cout << "Base2 destory" << endl; }
};
 
class Base3
{
public:
    Base3() { cout << "Base3" << endl; }
    ~Base3() { cout << "Base3 destory" << endl; }
};
 
class Base4
{
public:
    Base4() { cout << "Base4" << endl; }
    ~Base4() { cout << "Base4 destory" << endl; }
};
 
class Derived :public Base1, virtual public Base2,
    public Base3, virtual public Base4
{
public:
    Derived() { cout << "Derived ok" << endl; }
    ~Derived() { cout << "Derived destory" << endl; }
protected:
    OBJ1 obj1;
    OBJ2 obj2;
};
 
int main()
{
    Derived aa;
    cout << "construct ok"<<endl;
    return 0;
}

程序输出结果如下:

Base2
Base4
Base1
Base3
OBJ1
OBJ2
Derived ok
construct ok
Derived destory
OBJ2 destory
OBJ1 destory
Base3 destory
Base1 destory
Base4 destory
Base2 destory

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

全局变量储存在静态数据区,局部变量在堆栈中。

C++ 中的 new delete 和 C 语言中的 malloc free 有什么区别

虽然这两者都分别是完成分配内存和释放内存的功能,但是 C++new 分配内存时会调用构造函数,用 delete 释放内存时会调用析构函数。

new、delete、malloc、free 区别

  • newdeleteC++ 的运算符,mallocfree 是 C++/C 语言的标准框函数,都可用于申请动态内存和释放内存。
  • new 动过调用对象的构造函数来申请动态内存;delete 通过调用对象的析构函数来释放内存。
  • 对于非内部数据类型的对象而言,只用 maloc/free 是无法满足动态对象的要求。我们知道对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。但由于 malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于 malloc/free。因此 new/delete 其实比 malloc/free 更灵活。

static 关键字作用

  • 声明全局静态变量:在全局变量前加上关键字 static,全局变量就定义成一个全局静态变量,作用域在声明它的文件之外是不可见的,即从定义之处开始到文件结尾
  • 局部静态变量:在局部变量前加上关键字 static,作用域仍然为局部作用域,即当定义它的函数或者语句块结束的时候,作用域结束。
  • 静态函数: 在函数返回类型前加 static,静态函数只在声明他的文件中可见,不能被其他文件使用。
  • 类的静态成员:在类中,静态成员可以实现多个对象之间的数据共享,即静态成员是类的所有对象中共享的成员,而不是某个对象成员。并且使用静态数据成员不会破坏隐藏的原则,保证了数据的安全性。
  • 类的静态函数:把函数成员声明为静态的,就可以把函数与类的任何特定对象独立开来。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问(<类名>::<静态成员函数名>(<参数表>))

类的 static 变量在什么时候初始化?函数的 static 变量在什么时候初始化?

类的静态成员变量在类实例化之前就已经存在了,并且分配了内存。函数的static 变量在执行此函数时进行初始化。

C++ 变量作用域

作用域即是程序的一个区域,在程序中变量的作用域一般有三个地方:

  • 在函数或者一个代码块内部声明的变量,称为局部变量;
  • 在函数参数中定义的变量,称为形参;
  • 在所有函数外部声明的变量,比如在程序文件开头定义的变量,称为全局变量。

C++ 指针和引用的区别

  • 指针有自己的内存空间,而引用只是一个别名,类似于Python浅拷贝和深拷贝的区别
  • 不存在空引用, 引用必须链接到一块合法的内存地址;
  • 一旦引用被初始化为一个对象,就不能指向另一个对象。指针可以在任何时候指向任何一个对象;
  • 引用必须在创建时被初始化。指针可以在任何时间初始化。
  • 指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a 是不合法的)。

C++ 中析构函数的作用

析构函数与构造函数对应,类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。

C++ 静态函数和虚函数的区别

静态函数在编译的时候就已经确定运行时机,虚函数在运行的时候动态绑定。虚函数因为用了虚函数表机制,调用的时候会增加一次内存开销。

++i 和 i++ 区别

++i 先自增1,再返回,i++,先返回 i,再自增1.

const 关键字作用

const类型的对象在程序执行期间不能被修改改变。

C++如何传递数组给函数

首先要知道的是,C++ 传数组给一个函数,该数组类型会自动转换为指针,因此实际传递的是地址。

一维数组作为形参有以下三种方式,多维数组作为形参类似。

  • 形参是一个指针;
  • 形参是已定义大小的数组;
  • 形参是未定义大小的数组。
CPP程序 #include "stdio.h" #include #include #define getpch(type) (type*)malloc(sizeof(type)) #define NULL 0 struct pcb { /* 定义进程控制块PCB */ char name[10]; char state; int super; int ntime; int rtime; struct pcb* link; }*ready=NULL,*p; typedef struct pcb PCB; sort() /* 建立对进程进行优先级排列函数*/ { PCB *first, *second; int insert=0; if((ready==NULL)||((p->super)>(ready->super))) /*优先级最大者,插入队首*/ { p->link=ready; ready=p; } else /* 进程比较优先级,插入适当的位置中*/ { first=ready; second=first->link; while(second!=NULL) { if((p->super)>(second->super)) /*若插入进程比当前进程优先数大,*/ { /*插入到当前进程前面*/ p->link=second; first->link=p; second=NULL; insert=1; } else /* 插入进程优先数最低,则插入到队尾*/ { first=first->link; second=second->link; } } if(insert==0) first->link=p; } } input() /* 建立进程控制块函数*/ { int i,num; //clrscr(); /*清屏*/ printf("\n 请输入进程数?"); scanf("%d",&num); for(i=0;iname); printf("\n 输入进程优先数:"); scanf("%d",&p->super); printf("\n 输入进程运行时间:"); scanf("%d",&p->ntime); printf("\n"); p->rtime=0;p->state='w'; p->link=NULL; sort(); /* 调用sort函数*/ } } int space() { int l=0; PCB* pr=ready; while(pr!=NULL) { l++; pr=pr->link; } return(l); } disp(PCB * pr) /*建立进程显示函数,用于显示当前进程*/ { printf("\n qname \t state \t super \t ndtime \t runtime \n"); printf("|%s\t",pr->name); printf("|%c\t",pr->state); printf("|%d\t",pr->super); printf("|%d\t",pr->ntime); printf("|%d\t",pr->rtime); printf("\n"); } check() /* 建立进程查看函数 */ { PCB* pr; printf("\n **** 当前正在运行的进程是:%s",p->name); /*显示当前运行进程*/ disp(p); pr=ready; printf("\n ****当前就绪队列状态为:\n"); /*显示就绪队列状态*/ while(pr!=NULL) { disp(pr); pr=pr->link; } } destroy() /*建立进程撤消函数(进程运行结束,撤消进程)*/ { printf("\n 进程 [%s] 已完成.\n",p->name); free(p); } running() /* 建立进程就绪函数(进程运行时间到,置就绪状态*/ { (p->rtime)++; if(p->rtime==p->ntime) destroy(); /* 调用destroy函数*/ else { (p->super)--; p->state='w'; sort(); /*调用sort函数*/ } } main() /*主函数*/ { int len,h=0; char ch; input(); len=space(); while((len!=0)&&(ready!=NULL)) { ch=getchar(); h++; printf("\n The execute number:%d \n",h); p=ready; ready=p->link; p->link=NULL; p->state='R'; check(); running(); printf("\n 按任一键继续......"); ch=getchar(); } printf("\n\n 进程已经完成.\n"); ch=getchar(); }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

嵌入式视觉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值