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()