C++面试笔记(1)

1. C和C++的区别

C++面向对象的三大特性

C++面试笔记(1)

面向对象的三个基本特征:封装、继承、多态

1、封装:把客观事物封装成抽象的类,类进行信息隐藏

关键字 当前类 包内 子孙类 包外
public
protected ×
friendly × ×
private × × ×

2、继承:使用现有类的所有功能,并在无需编写原来的类的情况下对这些功能进行扩展

分为父类和子类

继承的过程,就是一般到特殊的过程

3、多态:允许将子类类型的指针赋值给父类类型的指针

实现多态有两种方式:

(1) 覆盖:子类重新定义父类的虚函数的做法

(2) 重载:允许存在多个同名函数,但是参数表不同

基类指针指向子类对象

作用

(1) 封装可以隐藏实现的细节,使得代码模块化

(2) 继承扩展已有的代码模块--代码复用

(3) 实现接口的重用

C语言和C++的区别

从思想上

-- C程序的的设计首先考虑的是如何听过一个过程,对输入进行运算处理得到输出,是一个结构化语言

-- C++首先考虑的是如何构造出一个对象模型,让这个模型能够契合与之对应的问题域。

C++ 与 C 的区别(细化)


2. 指针和引用的区别

浅谈 C++ 中指针和引用的区别


(1) 性质区别:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;

而引用跟原来的变量实质上是一个佛那个下,只不过是一个别名

(2) 指针可以多级、引用最多一级

(3) 指针可以为空、引用不能为空

(4) 指针在初始化为可以改变,引用不能

(5) sizeof(指针)=指针本身的大小 sizeof(引用)=所指向变量的大小


3. 野指针和悬空指针的区别

野(wild)指针与悬空(dangling)指针

野指针是指没有初始化的指针,野指针指向不可用的内存


悬空指针是指指针最初指向的内存已经被释放的一种指针


4. const和static之间的区别

const的作用:


(1) 修饰变量,说明该变量不可以被改变

(2) 修饰指针,分为指向常量的指针和指针常量

常量指针和指针常量

int _tmain(int argc, _TCHAR* argv[])
{
//定义变量
int a=1; //定义常量
const int b=2; //定义常量指针
const int *ptr1=&a; //定义指针常量,必须赋值
int* const ptr2=&a; //错误,不能把常量的地址赋给指针变量
int *ptr3=&b; //正确,可以把常量的地址赋给常量指针
const int* ptr4=&b; //错误,间接引用常量指针不可以修改内存中的数据
*ptr1=3; //正确,间接引用指针常量可以修改内存中的数据
*ptr2=4; //正确,常量指针可以指向其他变量
ptr1=&b; //错误,指针常量不可以指向其他变量
ptr2=&b; //常量指针常量,即不可以间接引用修改内存数据,也不可以指向别的变量
const int * const ptr5=&a; //错误,不可以间接引用修改内存数据
*ptr5=5; //错误,不可以修改指向的对象
ptr5=&b; return 0;
}

(3) 常量引用,经常用于形参类型,即避免了拷贝,又避免了函数对值的修改

(4) 修饰成员函数,说明该成员函数内不能修改成员变量。

// 类
class A
{
private:
const int a; // 常对象成员,只能在初始化列表赋值 public:
// 构造函数
A() { };
A(int x) : a(x) { }; // 初始化列表 // const可用于对重载函数的区分
int getValue(); // 普通成员函数
int getValue() const; // 常成员函数,不得修改类中的任何数据成员的值
}; void function()
{
// 对象
A b; // 普通对象,可以调用全部成员函数
const A a; // 常对象,只能调用常成员函数、更新常成员变量
const A *p = &a; // 常指针
const A &q = a; // 常引用 // 指针
char greeting[] = "Hello";
char* p1 = greeting; // 指针变量,指向字符数组变量
const char* p2 = greeting; // 指针变量,指向字符数组常量
char* const p3 = greeting; // 常指针,指向字符数组变量
const char* const p4 = greeting; // 常指针,指向字符数组常量
} // 函数
void function1(const int Var); // 传递过来的参数在函数内不可变
void function2(const char* Var); // 参数指针所指内容为常量
void function3(char* const Var); // 参数指针为常指针
void function4(const int& Var); // 引用参数在函数内为常量 // 函数返回值
const int function5(); // 返回一个常数
const int* function6(); // 返回一个指向常量的指针变量,使用:const int *p = function6();
int* const function7(); // 返回一个指向变量的常指针,使用:int* const p = function7();

static作用

(1) 修饰普通变量,修改变量的存储区域和生命周期,使变量存储在静态区,在 main 函数运行前就分配了空间,如果有初始值就用初始值初始化它,如果没有初始值系统用默认值初始化它。

(2) 修饰普通函数,表明函数的作用范围,仅在定义该函数的文件内才能使用。在多人开发项目时,为了防止与他人命令函数重名,可以将函数定位为 static。

(3) 修饰成员变量,修饰成员变量使所有的对象只保存一个该变量,而且不需要生成对象就可以访问该成员。

(4) 修饰成员函数,修饰成员函数使得不需要生成对象就可以访问该函数,但是在 static 函数内不能访问非静态成员。

5 this指针

C++ this 指针

在C++中。每一个对象都能通过this指针来访问自己的地址,this指针是所有成员函数的隐含参数。因此在成员函数内部,它可以用来指向调用对象

其中,友元函数没有this指针,因为友员不是类的成员,只有成员函数才有this指针

#include <iostream>

using namespace std;

class Box
{
public:
// 构造函数定义
Box(double l=2.0, double b=2.0, double h=2.0)
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
}
double Volume()
{
return length * breadth * height;
}
int compare(Box box)
{
return this->Volume() > box.Volume();
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
}; int main(void)
{
Box Box1(3.3, 1.2, 1.5); // Declare box1
Box Box2(8.5, 6.0, 2.0); // Declare box2 if(Box1.compare(Box2))
{
cout << "Box2 is smaller than Box1" <<endl;
}
else
{
cout << "Box2 is equal to or larger than Box1" <<endl;
}
return 0;
}

6 友元函数

类的友元函数是定义在类的外部,但有权访问类的私有和保护成员。尽管友元函数的原型在类的定义中,但是友元函数并不是成员函数

友元可以是一个函数,也可以是一个类;友元类的整个类及其所有成员都是友元

声明函数为友元:

#include <iostream>

using namespace std;

class Box
{
double width;
public:
friend void printWidth( Box box );
void setWidth( double wid );
}; // 成员函数定义
void Box::setWidth( double wid )
{
width = wid;
} // 请注意:printWidth() 不是任何类的成员函数
void printWidth( Box box )
{
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
cout << "Width of box : " << box.width <<endl;
} // 程序的主函数
int main( )
{
Box box; // 使用成员函数设置宽度
box.setWidth(10.0); // 使用友元函数输出宽度
printWidth( box ); return 0;
}

7. struct与class之间的区别

C++ 中结构体与类的区别

(1) 默认的访问控制:struct是public class是private

(2) Class还能用于定义模板参数,而struct不用于定义模板参数

struct更适合看成一个数据结构的实现体,class更适合看成是一个对象的实现体


8. 常见数据结构在32位和64位机器上的字节数

/ 32位 64位
char 1 1
指针变量 4 8
short 2 2
int 4 4
uint 4 4
float 4 4
double 8 8
long 4 8
long long 8 8
ulong long 4 8

9.虚函数可以inline吗?

引入inline的原因?

在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。

栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。

在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足而导致程序出错的问题,如,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。

类中除了虚函数的其他函数都会自动隐式地当成内联函数

(1) 虚函数是可以内联的,但是当虚函数表现多态时不能内联

(2) 内联是在编译器建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。

(3) inline virtual 唯一可以内联的时候是:编译器知道所调用的对象是哪个类(如 Base::who()),这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。

虚函数内联使用:

#include <iostream>
using namespace std;
class Base
{
public:
inline virtual void who()
{
cout << "I am Base\n";
}
virtual ~Base() {}
};
class Derived : public Base
{
public:
inline void who() // 不写inline时隐式内联
{
cout << "I am Derived\n";
}
}; int main()
{
// 此处的虚函数 who(),是通过类(Base)的具体对象(b)来调用的,编译期间就能确定了,所以它可以是内联的,但最终是否内联取决于编译器。
Base b;
b.who(); // 此处的虚函数是通过指针调用的,呈现多态性,需要在运行时期间才能确定,所以不能为内联。
Base *ptr = new Derived();
ptr->who(); // 因为Base有虚析构函数(virtual ~Base() {}),所以 delete 时,会先调用派生类(Derived)析构函数,再调用基类(Base)析构函数,防止内存泄漏。
delete ptr;
ptr = nullptr; system("pause");
return 0;
}

10 volatile关键字

C/C++ 中 volatile 关键字详解

谈谈 C/C++ 中的 volatile


上一篇:老调重弹--面向对象设计原则--S.O.L.I.D设计原则


下一篇:Vue实例中封装api接口的思路 在页面中用async,await调用方法请求