第二章 第二节 基本语言(二)

16 December 2021  |  home page


智能指针

为什么要使用智能指针:

智能指针的作用是管理一个指针,因为存在以下这种情况:申请的空间在函数结束时忘记释放,造成内存泄漏。使用智能指针可以很大程度上的避免这个问题,因为智能指针就是一个类,当超出了类的作用域是,类会自动调用析构函数,析构函数会自动释放资源。所以智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。

4种类型的指针

请你回答一下为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数 考点:虚函数 析构函数

将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。

C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存。而对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此C++默认的析构函数不是虚函数,而是只有当需要当作父类时,设置为虚函数。

虚函数与纯虚函数的区别

友元函数

tutorial

函数指针

fork 函数

C++ 析构函数

静态函数 vs 虚函数

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

重载 vs 重写

多态

虚函数机制

在有虚函数的类中,类的最开始部分是一个虚函数表的指针,这个指针指向一个虚函数表,表中放了虚函数的地址,实际的虚函数在代码段(.text)中。当子类继承了父类的时候也会继承其虚函数表,当子类重写父类中虚函数时候,会将其继承到的虚函数表中的地址替换为重新写的函数地址。使用了虚函数,会增加访问内存开销,降低效率。

以下四行代码的区别是什么?const char *arr = "123"; char* brr = "123"; const char crr[] = "123"; char drr[] = "123";

如果同时定义了两个函数,一个带const,一个不带,会有问题吗?

不会,相当于函数重载

隐式转换

// Example program
#include <iostream>
#include <string>


class Test{
    int test1;
    int test2;
    
public:
    friend void anything(Test t);
    
    Test(int test1, int test2){
        this->test1 = test1;
        this->test2 = test2;
    }
};

void anything(Test t){
    std::cout << "test inside: " << t.test1 << " " << t.test2 << std::endl;
}   

int main()
{
    anything({1, 2});
}

类型转换 (credit to ydar95)

extern “C”

在C中,由于C不支持函数重载(overloading), 所以编译器会给每个函数唯一的名字(即函数名),但由于C++支持多态,所以其编译器会为重载的函数生成不同的名字,这样的话会让C编译器看不懂(在把cpp与c的程序链接起来的时候出问题).
extern “C”{} 会保证{}内的函数符号不会mangle(破坏)

new/delete vs malloc/free

RTTI(Run-time type infomration) (retrieved from here)

In C++, RTTI (Run-time type information) is a mechanism that exposes information about an object’s data type at runtime and is available only for the classes which have at least one virtual function. It allows the type of an object to be determined during program execution

For example, dynamic_cast uses RTTI and following program fails with error “cannot dynamic_cast ‘b’ (of type ‘class B’) to type `class D’ (source type is not polymorphic) ” because there is no virtual function in the base class B.

// CPP program to illustrate 
// Run Time Type Identification 
#include<iostream>
using namespace std;
class B { };
class D: public B {};
  
int main()
{
    B *b = new D;
    D *d = dynamic_cast<D*>(b);
    if(d != NULL)
        cout<<"works";
    else
        cout<<"cannot cast B* to D*";
    getchar();
    return 0;
}

Adding a virtual function to the base class B makes it working.

// CPP program to illustrate 
// Run Time Type Identification 
#include<iostream>
using namespace std;
class B { virtual void fun() {} };
class D: public B { };
  
int main()
{
    B *b = new D;
    D *d = dynamic_cast<D*>(b);
    if(d != NULL)
        cout << "works";
    else
        cout << "cannot cast B* to D*";
    getchar();
    return 0;
}

运行时类型检查,在C++层面主要体现在dynamic_casttypeid,VS中虚函数表的-1位置存放了指向type_info的指针。对于存在虚函数的类型,typeid和dynamic_cast都会去查询type_info

C++如何处理返回值

生成一个临时变量,把它的引用作为函数参数传入函数内。

C++中拷贝构造函数能否进行值传递

不能.碰到函数调用需要以值传递的时候,会一直调用拷贝构造函数直至栈溢出

重载 vs. 重写

仿函数

变量类并重载operator()操作符来使类具有函数的性质

inline

explict

it cannot be used for implicit conversions and copy-initialization.




Hosted on GitHub Pages — Theme by orderedlist