【无标题】

一、类型转换

1、const_cast:

        编译时完成,不能去除变量本身的const、volatile属性。可以作用于指针/引用,修改指针/引用的属性,达到间接修改的目的。

        问题:const_cast修改值后,可能会被编译器优化导致错误。

void const_cast_T1(){
    const int a = 1;
    int &p = const_cast<int&> (a);
    p = 10;
    cout<<a<<endl<<p;
}

此时,输出a为1,p为10,这是因为因为编译器的优化,a没有从内存取值,而是直接读的内存器的值。(换成指针也一样)。

void const_cast_T2(){
    volatile const int a = 1;
    int &p = const_cast<int&> (a);
    p = 10;
    cout<<a<<endl<<p;
}

加上volatile属性,防止编译器优化,此时a与p输出值都为10。

2、static_cast 

        编译时完成,没有类型检查,不能去掉指针/引用的const与volatile属性。

        可以进行上行转换(子类指针/引用转换为基类指针/引用),下行转换可以,但是不安全。

3、dynamic_cast

        运行时完成,有类型检查,只能用于子类与基类之间指针/引用的上下行转换。转换失败会返回空指针,是安全的。

        使用动态转换时,基类中必须有虚函数,否则编译不通过。

        一般什么时候会向下转型?子类指针/引用向上转型为基类指针/引用后,想调用子类的成员方法,需要转型回来。

4、reinterpret_cast

        什么都可以转,少用,不安全。一般用于指针类型转换,告诉编译器如何去解释内存中的数据。

5、为什么不用C的强制转换?

        没有类型检查,不够安全。

二、指针与引用的区别

        1、空间、大小、初始化:指针是存储类型为地址的变量,会为其分配空间并初始化为NULL指针大小为4/8;  引用是变量的别名,不会为其分配空间,必须是一个已有对象的引用。编译器编译后与被引用对象一样。引用的大小与被引用对象一样。

        2、作为参数:

        3、多级:有多级指针,没有多级引用。

        4、运算符:指针++表示内存中递增;引用++表示运算。

        5、内存泄漏:动态分配内存时,使用引用可能造成泄露。

        泄露的原因在于疏忽,误以为引用是变量的引用。下列代码可正常释放内存:

void delete_test(){
    int & p = *new(int);
    delete &p;
}

        6、可变性:指针可以改变指向的内存,引用一旦初始化不可改变。

        7、const属性:指针有顶层const,引用没有顶层const。

      引用不能改变。没有引用的引用。

三、智能指针

        C++11支持的三种智能指针:shared_ptr,weak_ptr,unique_ptr。

        1、为什么使用智能指针:防止内存泄漏,智能指针可以帮助回收内存。

        2、智能指针通过什么管理内存:析构函数。

        3、智能指针一定安全吗:不一定。循环引用也会导致内存泄漏。解决办法:引入weak_ptr。

        4、三种类型的指针:

        unique_ptr:严格独占,保证同一时间只有一个智能指针指向该对象;如果将一个临时右值的u_ptr赋值给另一个时,编译器将允许这么做。unique_ptr禁用了拷贝与赋值,没有引用计数。可以通过move函数实现转移。

        shared_ptr:通过引用计数实现共享。

        weak_ptr:可以从一个shared_ptr或者weak_ptr构造。不控制对象生命周期,它的构造与析构不会引起引用计数的增加或者减少,用于解决shared_循环引用引起的死锁。不可以通过weak指针访问对象的方法。必须通过lock()函数转化为share_ptr。

        5、智能指针指向栈内存会发生什么?编译没有问题,运行时会崩溃。

四、数组与指针的区别

        

指针数组
保存地址保存数据
间接访问直接访问

五、什么是野指针

        野指针是指指针访问的位置不可知。

        1、 指针指向一个已经删除或者释放的对象。

        2、指针初始化时没有赋值或没有赋值为NULL,此时指针是随机值,此时指向的对象可能未被申请或者访问受限。      

        3、数组访问越界。

  六、fork()函数

        创建一个与当前进程一模一样的副本。如Linux的命令行,将会指向fork()函数。

  七、析构函数

        对象结束生命周期时调用。

        调用顺序:1)派生类本身析构函数 2)派生类成员析构函数 3)基类析构函数

八、静态函数与虚函数区别

        静态函数编译时已经确认运行机制,虚函数进行动态绑定。虚函数由于虚函数表机制,会增加内存开销。

九、strlen()与strcpy()

        strlen计算字符串的长度,返回从开始到‘\0’之间字符的个数。(不包括结束符)

       char* strcpy(char* d,const char *s)。由于参数不包括长度,存在越界隐患。安全版本为strnlen()。

十、++i与i++

        ++i:

int& operate++{
    *this+=1;
    return *this;
}

        i++:通过是否输入参数重载。

                为什么返回const?为了静止i++++操作。

const int int::operate++(int){
    int temp = *this;
    ++(*this);
    return temp;
}

十一、c++函数默认栈空间大小

        1M,可调整。

十二、库函数与关键字的区别?

        库函数是封装好的函数。

        关键字是该编程语言已经“占用”的词语,自己的程序里不能再把它定义成其他用途。关键字有可能是声明语句,也有可能是流程控制语句,也有可能是一部分内置函数。

十三、RTTI

        run-time Type Identification,运行时类型识别。dynamic_cast和虚函数会用到。

十四、typeid

        返回指针实际指向的对象类型。

十五、C语言如何实现函数调用

        每一个函数调用会为其分配函数栈,在栈内进行函数执行过程,调用前,先将返回地址压栈,然后把当前函数的esp指针压栈。

十六、函数参数压栈顺序

        从右到左。

十七、拷贝构造函数的形参不能进行值传递

        将实参拷贝给形参也要调用拷贝构造函数。形成了循环。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值