C++ constexpr 虚函数

文章详细解释了C++中的constexpr关键字用于编译期优化,以及虚函数实现的动态多态。constexpr确保了变量和表达式在编译时计算,而虚函数则允许在运行时决定函数调用的对象。文章还探讨了静态多态(包括函数重载和运算符重载)以及类的内存布局,特别是虚函数表在多继承情况下的表现。
摘要由CSDN通过智能技术生成

C++ constexpr + 虚函数

constexpr的使用

constexpr在c++中的使用主要用于做一些编译优化,在编译期间即可确定变量或者表达式的值信息。
例如下面的代码片段:

int A() {
   return 4;}
// 使用下面的代码会报错
std::array<int, sizeA> a;  // call to non-'constexpr' function

因为A是在执行阶段才能够确定其值,所以报错调用非constexpr的函数,如果将A函数改成constexpr就不会有报错,并且能够得到性能的优化

const int A() {
   return 4;}
std::array<int, sizeA> a;

此外,如果constexpr修饰的值是一个函数的返回值,那么该函数也需要用constexpr修饰,例如下面的代码片段

int f1(int a, int b) 
{
   
	return a + b;
}

constexpr int f2(int a, int b) 
{
   
	return a + b;
}

constexpr int a = f1(1, 2); // 报错,同样是call to non-'constexpr' function
constexpr int b = f2(3, 4); // 不报错

虚函数

多态本义为多种不同的状态,即调用一个函数可能出现不同的结果,在c++中多态通常包含两种,静态多态动态多态。静态多态主要通过重载实现,即相同的函数名,不同的函数参数类型,参数顺序,参数数量。还有运算符重载也算是静态多态。

静态多态

静态多态包含两类,分别是运算符重载和函数重载,函数重载的形式较为简单,下面的例子是函数重载。

// base function
double func1(int a, double b)
{
   
    return a + b;
}
// 不同的参数类型
double func1(double a, double b)
{
   
    return a + b;
}
// 不同参数顺序
double func1(double a, int b)
{
   
    return a + static_cast<double>(b);
}
// 不同的参数数量
double func1(double a)
{
   
    return a;
}

下面的函数不构成重载

// base function
double func1(int a, double b)
{
   
    return a + b;
}
// 仅有返回值不同不构成重载
int func1(double a, int b)
{
   
    return static_cast<int>(a) + b;
}

// 参数类型相同,名字不同不构成重载
double func1(double c, int d)
{
   
    return c + d;
}

插一段:类中的函数分类及存储

在类中通常包含两类函数,分别是静态函数,非静态函数,C++的内存通常包含四个区域,分别是常量区、代码区、栈区、堆区。

  • 常量区主要用于存放全局变量以及类中声明的静态变量、常量
  • 代码区主要用于存放静态函数,非静态函数的代码内容
  • 栈区主要用于存放局部变量、函数参数、返回数据、返回地址
  • 堆区主要用于存放动态分配的内存信息

静态成员函数和非静态成员函数,是在类定义时存放在内存的代码区的,类可以直接调用静态函数,但类无法调用非静态成员函数,只有类的对象才能够调用非静态成员函数,这是因为非静态成员函数内部有一个指向类对象的指针类型参数(this),只有在类对象调用时,才能够使得this有实际的值。

动态多态

动态多态主要通过虚函数来实现,虚函数是类中的一类函数,通过virtual实现。虚函数也依靠继承实现。首先看一下普通的继承。

单继承
class Father
{
   
public:
    explicit Father(int a): a(a)
    {
   
        cout << "father execute" << endl;
    }
    ~Father()
    {
   
        cout << "father release" << endl;
    }
private:
    int a;
};

class Children: public Father
{
   
public:
    explicit Children(int a, int b): Father(a), b(b)
    {
   
        cout << "Children execute" << endl;
    }
    ~Children()
    {
   
        cout << "Children release" << endl;
    }

private:
    int b;
};

Children t(1, 2); 
cout << "Test" << endl;
// 上面的代码执行结果是什么?

执行结果输出的前两句是通过构造函数实现的,后面两句是通过析构函数实现的。在调用Children的构造函数时,通过Father(a)先调用了Father的构造函数,然后第一个输出输出(1) father execute,之后执行Children的构造函数代码体,输出(2) Children execute。在执行完main函数之后,输出(3) Test。之后进行回收工作,执行Children的析构函数,输出(4) Children release,最后还要执行父类的析构函数,输出(5) father release,最终的输出结果如下

father execute
Children execute
Test
Children release
father release

在类中加入虚函数后,如下

class Father
{
   
public:
    explicit Father(int a): a(a)
    {
   
        cout << "father execute" << endl;
    }

    virtual void f(){
   }
    virtual void g()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值