C/C++常见面试题整理(持续更新)

C/C++语法知识相关

指针和引用区别

  1. 引用不可以为空,指针可以为空
  2. 引用必须初始化,而且一旦初始化后不能更改(只能是初始化时变量的引用),指针可以更改指向
  3. 对指针和引用进行运算操作时结果不同。比如对引用进行++,改变引用的对象,对指针进行++,指针移动位置,指向别的变量
  4. 引用大小为所指向变量的大小,指针大小为指针本身大小。
  5. 引用比指针更安全。指针存在野指针问题。
  6. 可以有const指针,没有const引用(因为引用本身就是常量)
  7. 指针可以有多级,引用只可以有一级
  8. 传递参数时,指针传递的是参数的拷贝,引用传递的是本身

虚函数和纯虚函数

  • 定义一个函数为虚函数,不代表函数为不被实现的函数,是为了允许基类指针调用子类函数
  • 定义一个函数为纯虚函数,是为了实现一个接口,基本不进行实现,子类必须实现
  • 析构函数应当是虚函数,将调用相应对象类型的析构函数,因此,如果指针指向的是子类对象,将调用子类的析构函数,然后自动调用基类的析构函数

参考:https://www.cnblogs.com/ganxiang/p/13054500.html

public,protected,private

用户代码(类外)可以访问public成员而不能访问private成员;private成员只能由类成员(类内)和友元访问。

protected成员可以被派生类对象访问,不能被用户代码(类外)访问。

public继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:public, protected, private

protected继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:protected, protected, private

private继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:private, private, private

静态多态和动态多态

静态多态:也称为编译期间的多态,编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式类型转换),可推断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。

静态多态有两种实现方式:

  • 函数重载:包括普通函数的重载和成员函数的重载
  • 函数模板的使用

动态多态(动态绑定):即运行时的多态,在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的方法。

虚继承

解决多继承中的冲突问题

类B和类C继承自类A,类D继承了类B和类C,这时类D拥有了两份类A中的成员,如果类B和类C为虚继承自类A,那么类D仅拥有一份类A的成员。

C++空类默认产生哪些成员函数?

默认构造函数、默认拷贝构造函数、默认析构函数、默认赋值运算符、取址运算符和取址运算符const

   1: class Empty
   2:  
   3: {
   4:  
   5:   public:
   6:  
   7:       Empty(); // 缺省构造函数
   8:  
   9:       Empty( const Empty& ); // 拷贝构造函数
  10:  
  11:       ~Empty(); // 析构函数
  12:  
  13:        Empty& operator=( const Empty& ); // 赋值运算符
  14:  
  15:        Empty* operator&(); // 取址运算符
  16:  
  17:        const Empty* operator&() const; // 取址运算符 const
  18:  
  19: };

C++默认生成的构造函数,只要在被需要的时候,才会产生。即当我们定义一个类,而不创建类的对象时,就不会创建类的构造函数,析构函数等。

重载、重写、隐藏区别

重载

同一作用域中,同名函数形式参数不同(参数个数、类型、顺序不同),构成函数重载。

注意

  • 函数返回值类型与构成重载无任何关系
  • 类的静态成员函数与普通成员函数可以形成重载
  • 函数重载发生在同一作用域,如类成员之间的重载,全局函数之间的重载
  • C++不能被重载的运算符:"."(成员访问运算符),"*"(成员指针访问运算符),"::"(作用域运算符),sizeof,?:(条件运算符)【前两个运算符不能被重载时为了保证访问成员的功能不变,域运算符和sizeof运算符的运算对象是类型而不是变量或一般表达式,不具备重载的特征】
class A{
public:
    void test(int i);
    void test(double i); //overload
    void test(int i,double j); //overload
    void test(double i,int j);//overload
    int test(int i);  //错误,非重载。重载不关心函数返回类型
};

隐藏

不同作用域中定义的同名函数构成隐藏(不要求函数返回值和函数参数类型相同)。比如派生类成员函数隐藏与其同名的基类成员函数、类成员函数隐藏全局外部函数

  • 子类函数与父类名称相同,但是参数不同父类函数被隐藏
  • 子类函数与父类函数名称相同参数相同,但是父类函数没有virutal父类函数被隐藏
  • 子类函数与父类函数名称相同参数相同,但是父类函数有virutal父类函数被覆盖
#include<iostream>

using namespace std;

class Base{
public:
    void fun(double,int){
        cout<<"Base::fun(double,int)"<<endl;
    }
};
class Derive :public Base
{
public:
    void fun(int) {
        cout<<"Derive::fun(int)"<<endl;
    }
};
int main()
{
    Derive pd;
    pd.fun(1);//Derive::fun(int),父类函数被隐藏
    //pd.fun(0.01,1);//父类函数被隐藏,error:"Derive::fun":函数不接受两个参数

    Base *fd = &pd;
    fd->fun(1.0,1);//Base::fun(double,int);
    fd->fun(1);//error:no matching function for call to "Base::fun(int)"

    return 0;
}

覆盖

子类覆盖父类函数

  • 分别位于子类和父类中
  • 函数名字与参数相同
  • 父类函数是虚函数(virtual)
#include<iostream>

using namespace std;

class Base{
public:
    virtual void  f(float x){
        cout<<"Base::f(float)"<<x<<endl;
    }
    void g(float x){
        cout<<"Base::g(float)"<<x<<endl;
    }
    void h(float x){
        cout<<"Base::h(float)"<<x<<endl;
    }
};
class Derived:public Base
{
public:
    virtual void f(float x){
        cout<<"Derived::f(float)"<<x<<endl;
    }
    void g(int x){
        cout<<"Derived::g(int)"<<x<<endl;
    }
    void h(float x){
        cout<<"Derived::h(float)"<<x<<endl;
    }
};
int main()
{
    Derived d;
    Base *pb = &d;
    Derived *fd = &d;

    //Good:behavior depends solely on thpe of the object
    pb->f(3.14f);//Derived::f(float) 3.14
    fd->f(3.14f);//Derived::f(float) 3.14
    //Bad:behavior depends on type of the pointer
    pb->g(3.14f);//Base::g(float)3.14
    fd->g(3.14f);//Derived::g(int) 3
    //Bad:behavior depends on type of the pointer
    pb->h(3.14f);//Base::h(float) 3.14
    fd->h(3.14f);//Derived::h(float) 3.14

    return 0;
}

vector使用注意事项

  1. 当程序重复之星一段代码时,之前保存数据用的vector需要清空
  2. 清空vector数据时,如果保存的数据项是指针类型,需要逐项delete,否则会造成内存泄漏
  3. 当插入或删除元素后,注意避免操作迭代器,因为迭代器发生变化,已经失效

map、set、unordered_map、unordered_set ,multimap,multiset

map的insert方法会忽略重复key值,而不是替换,[]方法会对已经存在的key值对应的value进行覆盖

map的插入方法

map<int, string> mapStu;
    //插入方式1
    mapStu.insert(pair<int, string>(3,"abcd"));
    //插入方式2
    mapStu.insert(map<int, string>::value_type(1,"dfgh"));
    //插入方式3
    //这种方法非常直观,但是存在一个性能问题。插入2时,先在mapStu中查找主键为3的项,若没发现,则将 
     //一个键为3,值为初始化的对组插入到mapStu中,然后再将值修改为"asdf"。若发现已存在3这个键,则 
     //修改这个键对应的value
    mapStu[2] = "asdf";
    
    //输出方式1
    for(auto it = mapStu.begin();it!=mapStu.end();++it)
        cout<<(*it).first<<" "<<(*it).second<<endl;
    //输出方式2
    for(auto it = mapStu.begin();it!=mapStu.end();++it)
        cout<<it->first<<" "<<it->second<<endl;

    map<T1, T2,less<T1>> mapA;//该容器是按照键的升序方式排列元素
    map<T1, T2,greater<T1>> mapB;//该容器是按键的降序方式排序

    //返回键值大于等于key的第一个元素
    lower_bound(key);
    //返回键值大于key的第一个元素
    upper_bound(key);
    //返回键值等于key的元素区间
    equal_range(key);

map支持[]操作符,multimap不支持[]操作符

map和set的底层实现为红黑树

unordered_map和unordered_set底层实现为哈希表

string

IO操作

使用cin读取字符串时,遇到空白就停止读取,比如程序输入的是

"  hello  world"

那么得到的字符串是"hello",前面的空白没了,后面的world也读不出来

如果想要把整个hello world读进来,应该定义两个字符串,分别进行读取

cin>>s1>>s2;

hello存在s1里,world存在s2里。

也可以使用getline方法获取一整行内容

string s;
getline(cin, s);

list

list是双向链表

forward_list是单向链表

list容器不能调用algorightm下的sort函数进行排序,因为sort函数要求容器必须可以随机存储,而list做不到,因此list有自己的排序函数。

list<int> l = {2,3,5,5,6,7,89,0};
for(auto it = l.begin();it!=l.end();++it)
{
    cout<<*it<<' ';
}
cout<<endl;
l.sort();

for(auto it = l.begin();it!=l.end();++it)
{
   cout<<*it<<' ';
}
cout<<endl;

C++11新特性

nullptr

nullptr 出现的目的是为了替代 NULL。

在某种意义上来说,传统 C++ 会把 NULL、0 视为同一种东西,这

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值