注册公司后才可以做独立网站吗/在线外链
注意: 本内容为摘抄网上的学习资料,作为个人笔记使用,如有侵权, 立刻删除。
C++语言特性
1.关键字
(1)static
static全局变量和普通全局变量
面试高频指数:★★★☆☆
相同点:
- 存储方式:普通全局变量和 static 全局变量都是静态存储方式(编译时分配内存)。
不同点:
- 作用域:普通全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,普通全局变量在各个源文件中都是有效的;静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域限于一个源文件(编译模块)内,只能为该源文件内的函数公用,因此可以避免在其他源文件中引起错误。
例如在a.c中定义了static int a=10;
那么在b.c中用extern int a
是拿不到a的值得,a的作用域只在a.c中。
-
初始化:
- static修饰普通变量,修改变量的存储区域和生命周期,使变量存储在静态区,在 main 函数运行前就分配了空间,如果有初始值就用初始值初始化它,如果没有初始值系统用默认值(比如整型的0)初始化它。
- 用static声明局部变量-------局部变量指在代码块 {} 内部定义的变量,只在代码块内部有效(作用域),用static声明局部变量时,则改变变量的存储方式(生命期),使变量成为静态的局部变量,即编译时就为变量分配内存,直到程序退出才释放存储单元。这样,使得该局部变量有记忆功能,可以记忆上次的数据,不过由于仍是局部变量,因而只能在代码块内部使用(作用域不变)。
- 修饰成员变量,在类中,静态成员可以实现多个对象之间的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。因此,静态成员是类的所有对象中共享的成员,而不是某个对象的成员。对多个对象来说,静态数据成员只存储一处,供所有对象共用
-
修饰普通函数,表明函数的作用范围,仅在定义该函数的文件内才能使用。在多人开发项目时,为了防止与他人命名空间里的函数重名,可以将函数定位为 static。
如果想要其他文件可以引用本地函数,则要在函数定义时使用关键字extern,表示该函数是外部函数,可供其他文件调用。另外在要引用别的文件中定义的外部函数的文件中,使用extern声明要用的外部函数即可。
-
修饰成员函数
静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。
在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员(这点非常重要)。
如果静态成员函数中要引用非静态成员时,可通过对象来引用。从中可看出,调用静态成员函数使用如下格式:<类名>::<静态成员函数名>(<参数表>);
返回函数中静态变量的地址会发生什么?
面试高频指数:★★☆☆☆
#include <iostream>
using namespace std;int * fun(int tmp){static int var = 10;var *= tmp;return &var;
}int main() {cout << *fun(5) << endl;return 0;
}/*
运行结果:
50
*/
说明:上述代码中在函数 fun 中定义了静态局部变量 var,使得离开该函数的作用域后,该变量不会销毁,返回到主函数中,该变量依然存在,从而使程序得到正确的运行结果。但是,该静态局部变量直到程序运行结束后才销毁,浪费内存空间。
静态变量什么时候初始化
-
初始化只有一次,但是可以多次赋值,在主程序之前,编译器已经为其分配好了内存。
-
静态局部变量和全局变量一样,数据都存放在全局区域,所以在主程序之前,编译器已经为其分配好了内存,但在C和C++中静态局部变量的初始化节点又有点不太一样。在C中,初始化发生在代码执行之前,编译阶段分配好内存之后,就会进行初始化,所以我们看到在C语言中无法使用变量对静态局部变量进行初始化,在程序运行结束,变量所处的全局内存会被全部回收。
-
而在C++中,初始化时在执行相关代码时才会进行初始化,主要是由于C++引入对象后,要进行初始化必须执行相应构造函数和析构函数,在构造函数或析构函数中经常会需要进行某些程序中需要进行的特定操作,并非简单地分配内存。所以C++标准定为全局或静态对象是有首次用到时才会进行构造,并通过atexit()来管理。在程序结束,按照构造顺序反方向进行逐个析构。所以在C++中是可以使用变量对静态局部变量进行初始化的。
static 静态成员变量:
面试高频指数:★★★★★
- 静态成员变量是在类内进行声明,在类外进行定义和初始化,在类外进行定义和初始化的时候不要出现 static 关键字和private、public、protected 访问规则。
- 静态成员变量相当于类域中的全局变量,被类的所有对象所共享,包括派生类的对象。
疑问:派生类是什么? - 静态成员变量可以作为成员函数的参数,而普通成员变量不可以。
#include <iostream>
using namespace std;class A
{
public:static int s_var;int var;void fun1(int i = s_var); // 正确,静态成员变量可以作为成员函数的参数void fun2(int i = var); // error: invalid use of non-static data member 'A::var'
};
int main()
{return 0;
}
- 静态数据成员的类型可以是所属类的类型,而普通数据成员的类型只能是该类类型的指针或引用。
疑问:指针 引用 分别是什么意思?
#include <iostream>
using namespace std;class A
{
public:static A s_var; // 正确,静态数据成员A var; // error: field 'var' has incomplete type 'A'A *p; // 正确,指针A &var1; // 正确,引用
};int main()
{return 0;
}
static 静态成员函数:
-
静态成员函数不能调用非静态成员变量或者非静态成员函数,因为静态成员函数没有 this 指针,必须通过类名才能访问。静态成员函数做为类作用域的全局函数。
疑问:this指针是什么?怎么用? -
静态成员函数不能声明成虚函数(virtual)、const 函数和 volatile 函数。
疑问:虚函数、const 函数、volatile 函数 是什么?
(2) volatile
volatile 的作用?是否具有原子性,对编译器有什么影响?
面试高频指数:★★☆☆☆
-
volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素(操作系统、硬件、其它线程等)更改。所以使用 volatile 告诉编译器不应对这样的对象进行优化(意思就是告诉编译器不要忽略这样的对象)。
-
volatile 关键字声明的变量,每次访问时都必须从内存中取出值(没有被 volatile 修饰的变量,可能由于编译器的优化,从 CPU 寄存器中取值),保证对特殊地址的稳定访问
-
const 可以是 volatile (如只读的状态寄存器)
-
指针可以是 volatile
-
volatile不具有原子性。
-
注意:
- 可以把一个非volatile int赋给volatile int,但是不能把非volatile对象赋给一个volatile对象。
- 除了基本类型外,对用户定义类型也可以用volatile类型进行修饰。
- C++中一个有volatile标识符的类只能访问它接口的子集,一个由类的实现者控制的子集。用户只能用const_cast来获得对类型接口的完全访问。此外,volatile向const一样会从类传递到它的成员。
什么情况下一定要用 volatile, 能否和 const 一起使用?
面试高频指数:★★☆☆☆
使用 volatile 关键字的场景:
-
当多个线程都会用到某一变量,并且该变量的值有可能发生改变时,需要用 volatile 关键字对该变量进行修饰;
-
中断服务程序中访问的变量或并行设备的硬件寄存器的变量,最好用 volatile 关键字修饰。
volatile 关键字和 const 关键字可以同时使用,某种类型可以既是 volatile 又是 const ,同时具有二者的属性。
关键字volatile有什么含意?
答案:一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
volatile关键字
volatile int i = 10;
- volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素(操作系统、硬件、其它线程等)更改。所以使用 volatile 告诉编译器不应对这样的对象进行优化。
- volatile 关键字声明的变量,每次访问时都必须从内存中取出值(没有被 volatile 修饰的变量,可能由于编译器的优化,从 CPU 寄存器中取值)
- const 可以是 volatile (如只读的状态寄存器)
- 指针可以是 volatile
const, volatile区别
(1)const含义是“请做为常量使用”,而并非“放心吧,那肯定是个常量”,是不可修改的只读变量。
volatile的含义是“请不要做自以为是的优化,这个值可能变掉的”,而并非“你可以修改这个值”。
(2)const只在编译期有用,在运行期无用
const在编译期保证在C的“源代码”里面,没有对其修饰的变量进行修改的地方(如有则报错,编译不通过),而运行期该变量的值是否被改变则不受const的限制。
volatile在编译期和运行期都有用
在编译期告诉编译器:请不要做自以为是的优化,这个变量的值可能会变掉;
在运行期:每次用到该变量的值,都直接从内存中取该变量的值。
(3)const, volatile同时修饰一个变量
合法性
“volatile”的含义并非是“non-const”,volatile 和 const 不构成反义词,所以可以放一起修饰一个变量。
同时修饰一个变量的含义:表示一个变量在程序编译期不能被修改且不能被优化;在程序运行期,变量值可修改,但每次用到该变量的值都要从内存中读取,以防止意外错误。
(3)extern
请你来说一说extern“C”
参考回答:
- 被 extern 限定的函数或变量是 extern 类型的
- 被
extern "C"
修饰的变量和函数是按照 C 语言方式编译和链接的
extern "C"
的作用是让 C++ 编译器将extern "C"
声明的代码当作 C 语言代码处理,可以避免 C++ 因符号修饰导致代码不能和C语言库中的符号进行链接的问题。
extern “C” 使用
#ifdef __cplusplus
extern "C" {
#endifvoid *memset(void *, int, size_t);#ifdef __cplusplus
}
#endif
extern C为什么需要?
原因:c和c++ 对同一个函数经过编译后生成的函数名是不同的,由于C++ 支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。如果在c++ 中调用一个使用c语言编写的模块中的某个函数,那么c++ 是根据c++ 的名称修饰方式来查找并链接这个函数,那么就会发生链接错误。
extern 关键字作用
基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。此外extern也可用来进行链接指定。
也就是说extern有两个作用。第一,当它与"C"一起连用时,如: extern “C” void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的。
第二,当extern不与"C"在一起修饰变量或函数时,如在头文件中: extern int g_Int; 它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块或其他模块中使用,记住**它是一个声明不是定义!**也就是说B模块(编译单元)要是引用模块(编译单元)A中定义的全局变量或函数时,它只要包含A模块的头文件即可,在编译阶段,模块B虽然找不到该函数或变量,但它不会报错,它会在连接时从模块A生成的目标代码中找到此函数。
(4)const
面试高频指数:★★★☆☆
作用:
- const 修饰成员变量,定义成 const 常量,相较于宏常量,可进行类型检查,节省内存空间,提高了效率。
- const 修饰函数参数,使得传递过来的函数参数的值不能改变。
- const 修饰成员函数,使得成员函数不能修改任何类型的成员变量(mutable 修饰的变量除外),也不能调用非 const 成员函数,因为非 const 成员函数可能会修改成员变量。
在类中的用法:
const
成员变量:
-
const 成员变量只能在类内声明、定义,在构造函数初始化列表中初始化。
-
const 成员变量只在某个对象的生存周期内是常量,对于整个类而言却是可变的,因为类可以创建多个对象,不同类的 const 成员变量的值是不同的。因此不能在类的声明中初始化 const 成员变量,类的对象还没有创建,编译器不知道他的值。
const
成员函数:
不能修改成员变量的值,除非有 mutable 修饰;只能访问成员变量。
不能调用非常量成员函数,以防修改成员变量的值。
疑问:下面的代码 A(int tmp) : var(tmp) {}
没看懂
#include <iostream>
using namespace std;class A
{
public:int var;A(int tmp) : var(tmp) {}void c_fun(int tmp) const // const 成员函数{var = tmp; // error: assignment of member 'A::var' in read-only object. 在 const 成员函数中,不能修改任何类成员变量。 fun(tmp); // error: passing 'const A' as 'this' argument discards qualifiers. const 成员函数不能调用非 const 成员函数,因为非 const 成员函数可能会修改成员变量。}void fun(int tmp){var = tmp;}
};int main()
{return 0;
}
请你来说一下C++里是怎么定义常量的?常量存放在内存的哪个位置?
常量在C++里的定义就是一个top-level const加上对象类型,常量定义必须初始化。
- 对于局部对象,常量存放在栈区,
- 对于全局对象,常量存放在全局/静态存储区。
- 对于字面值常量,常量存放在常量存储区。
疑问?字面值常量是什么?
const作用 “只读”
- const修饰变量,以下两种定义形式在本质上是一样的。它的含义是:const修饰的类型为TYPE的变量value是不可变的。
TYPE const ValueName = value;const TYPE ValueName = value;
- 修饰指针
- 指向常量的指针(pointer to const)
- 自身是常量的指针(常量指针,const pointer)
- 修饰引用
- 指向常量的引用(reference to const)如果用于形参类型,即避免了拷贝,又避免了函数对值的修改;
- 没有 const reference,因为引用只是对象的别名,引用不是对象,不能用 const 修饰
- 修饰成员函数,说明该成员函数内不能修改成员变量。const修饰的成员函数表明函数调用不会对对象做出任何更改,事实上,如果确认不会对对象做更改,就应该为函数加上const限定,这样无论const对象还是普通对象都可以调用该函数。
const 使用
(为了方便记忆可以想成)被 const 修饰(在 const 后面)的值不可改变,如下文使用例子中的
p2
、p3
实际上const和*的优先级相同,且是从右相左读的,即“右左法则”
疑问:下面的 ** 已经让我懵逼
比如int*p;//读作p为指针,指向int,所以p为指向int的指针int*const p;//读作p为常量,是指针,指向int,所以p为指向int的常量指针, p不可修改int const *p;//p为指针,指向常量,为int,所以p为指向int常量的指针, *p不可修改int ** const p; //p为常量,指向指针,指针指向int,所以p为指向int型指针的常量指针,p不可修改const int **p;//指向常量指针的指针int const**p; //p为指针,指向指针,指针指向常量int,所以p为指针,指向一个指向int常量的指针, **p为int,不可修改int * const *p ; //p为指针,指向常量,该常量为指针,指向int,所以p为指针,指向一个常量指针,*p为指针,不可修改int ** const *p; //p为指针,指向常量,常量为指向指针的指针,p为指针,指向常量型指针的指针,*p为指向指针的指针,不可修改int * const **p; //p为指针,指向一个指针1,指针1指向一个常量,常量为指向int的指针,即p为指针,指向一个指向常量指针的指针, **p为指向一个int的指针,不可修改
== 为什么? const A &q = a; // 指向常对象的引用 ==
// 类
class A
{
private:const int a; // 常对象成员,可以使用初始化列表或者类内初始化public:// 构造函数A() : a(0) { };A(int x) : a(x) { }; // 初始化列表// const可用于对重载函数的区分int getValue(); // 普通成员函数int getValue() const; // 常成员函数,不得修改类中的任何数据成员的值
};void function()
{// 对象A b; // 普通对象,可以调用全部成员函数const A a; // 常对象,只能调用常成员函数const A *p = &a; // 指针变量,指向常对象const A &q = a; // 指向常对象的引用 // 指针char greeting[] = "Hello"; //字符串hello保存在栈区,可以通过greeting去修改const char * arr = "123"; //字符串123保存在常量区,const本来是修饰arr指向的值不能通过arr去修改,但是字符串“123”在常量区,本来就不能改变,所以加不加const效果都一样char * brr = "123"; //字符串123保存在常量区,这个arr指针指向的是同一个位置,同样不能通过brr去修改"123"的值const char crr[] = "123";//这里123本来是在栈上的,但是编译器可能会做某些优化,将其放到常量区
//确实,经过简单测试const char crr[]="123"; crr[1]='5';结果报错
//error: assignment of read-only location ‘crr[1]’char* p1 = greeting; // 指针变量,指向字符数组变量const char* p2 = greeting; // 指针变量,指向字符数组常量(const 后面是 char,说明不能通过p2修改greeting,但是greeting在栈上可以通过其它方式修改,比如下标,和p1来修改)char* const p3 = greeting; // 自身是常量的指针,指向字符数组变量(const 后面是 p3,说明 p3 指针自身不可改变,即指针不能指向其它地址,但可以修改其中的值)//比如*(p2+1)='c'; 则报错assignment of read-only location ‘*(p2 + 1u)’const char* const p4 = greeting; // 自身是常量的指针,指向字符数组常量
}
函数中使用const
(1)const修饰函数参数
a.传递过来的参数在函数内不可以改变(无意义,因为Var本身就是形参)void function(const int Var);b.参数指针所指内容为常量不可变void function(const char* Var);c.参数指针本身为常量不可变(也无意义,因为char* Var也是形参)void function(char* const Var);d.参数为引用,为了增加效率同时防止修改。修饰引用参数时:void function(const Class& Var); //引用参数在函数内不可以改变void function(const TYPE& Var); //引用参数在函数内为常量不可变
这样的一个const引用传递和最普通的函数按值传递的效果是一模一样的,他禁止对引用的对象的一切修改,唯一不同的是按值传递会先建立一个类对象的副本, 然后传递过去,而它直接传递地址,所以这种传递比按值传递更有效.另外只有引用的const传递可以传递一个临时对象,因为临时对象都是const属性, 且是不可见的,他短时间存在一个局部域中,所以不能使用指针,只有引用的const传递能够捕捉到这个家伙.
(2)const 修饰函数返回值
const修饰函数返回值其实用的并不是很多,它的含义和const修饰普通变量以及指针的含义基本相同。
const int fun1() //返回一个常数,这个其实无意义,因为参数返回本身就是赋值。const int * fun2() //返回一个指向常量的指针变量,使用如下const int *pValue = fun2(); //我们可以把fun2()看作成一个变量,即指针内容不可变。int* const fun3() //返回一个指向变量的常指针int * const pValue = fun2(); //我们可以把fun2()看作成一个变量,即指针本身不可变。
const与define
const
- const 常量限定符,声明的常量只读,不允许修改
- 在 C++ (不是 C) 中可以用 const 值声明数组长度
- 对于全局 const 值,C++ 中默认是内部链接(跟 static 一样只允许在本文件内可见),而不是 C 中的默认外部链接,若想在其他文件中使用必须在其他文件中重新定义或将 const 值放在头文件中(默认是外部链接放在头文件中编译可能会出现错误,默认是内部链接就不会出错)
define
-
编译阶段:define 是在编译预处理阶段进行替换,const 是在编译阶段确定其值。
-
安全性:define 定义的宏常量没有数据类型,只是进行简单的替换,不会进行类型安全的检查;const 定义的常量是有类型的,是要进行判断的,可以避免一些低级的错误。
-
内存占用:define 定义的宏常量,在程序中使用多少次就会进行多少次替换,内存中有多个备份,占用的是代码段的空间;const 定义的常量占用静态存储区的空间,程序运行过程中只有一份。
-
调试:define 定义的宏常量不能调试,因为在预编译阶段就已经进行替换了;const 定义的常量可以进行调试。
C++ 中推荐使用 const 代替 #define 声明常量
- const 能够明确指定常量类型
- const 能够用于更复杂的数据类型(如:数组,结构体和类)
- const 标识符遵循变量的作用域规则,可以创建作用域为全局(仅在本文件中使用)、命名空间、函数或数据块的常量
(5)mutable
mutable的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。我们知道,如果类的成员函数不会改变对象的状态,那么这个成员函数一般会声明成const的。但是,有些时候,我们需要在const函数里面修改一些跟类状态无关的数据成员,那么这个函数就应该被mutable来修饰,并且放在函数后后面关键字位置。
(6)inline
面试高频指数:★★★☆☆
作用:
inline
是一个关键字,可以用于定义内联函数。内联函数,像普通函数一样被调用,但是在调用时并不通过函数调用的机制而是直接在调用点处展开,这样可以大大减少由函数调用带来的开销,从而提高程序的运行效率。
特征
- 相当于把内联函数里面的内容写在调用内联函数处;
- 相当于不用执行进入函数的步骤,直接执行函数体;
- 相当于宏,却比宏多了类型检查,真正具有函数特性;宏是什么?
- 编译器一般不内联包含循环、递归、switch 等复杂操作的内联函数;
- 在类声明中定义的函数,除了虚函数的其他函数都会自动隐式地当成内联函数。
使用方法:
- 类内定义成员函数默认是内联函数
在类内定义成员函数,可以不用在函数头部加 inline 关键字,因为编译器会自动将类内定义的函数(构造函数、析构函数、普通成员函数等)声明为内联函数,代码如下:
#include <iostream>
using namespace std;class A{
public:int var;A(int tmp){ var = tmp;} //这句不懂??void fun(){ cout << var << endl;}
};int main()
{ return 0;
}
- 类外定义成员函数,若想定义为内联函数,需用关键字声明
当在类内声明函数,在类外定义函数时,如果想将该函数定义为内联函数,则可以在类内声明时不加 inline 关键字,而在类外定义函数时加上 inline 关键字。
#include <iostream>
using namespace std;class A{
public:int var;A(int tmp){ var = tmp;} void fun();
};inline void A::fun(){cout << var << endl;
}int main()
{ return 0;
}
另外,可以在声明函数和定义函数的同时加上 inline;也可以只在函数声明时加 inline,而定义函数时不加 inline。只要确保在调用该函数之前把 inline 的信息告知编译器即可。
inline 函数工作原理
面试高频指数:★★☆☆☆
-
内联函数不是在调用时发生控制转移关系,而是在编译阶段将函数体嵌入到每一个调用该函数的语句块中,编译器会将程序中出现内联函数的调用表达式用内联函数的函数体来替换。
-
普通函数是将程序执行转移到被调用函数所存放的内存地址,当函数执行完后,返回到执行此函数前的地方。转移操作需要保护现场,被调函数执行完后,再恢复现场,该过程需要较大的资源开销。
编译器对 inline 函数的处理步骤
- 将 inline 函数体复制到 inline 函数调用点处;
- 为所用 inline 函数中的局部变量分配内存空间;
- 将 inline 函数的的输入参数和返回值映射到调用方法的局部变量空间中;
- 如果 inline 函数有多个返回点,将其转变为 inline 函数代码块末尾的分支(使用 GOTO)。
inline 优缺点
优点:
-
inline定义的内联函数,函数代码被放入符号表中,在使用时进行替换(内联函数同宏函数一样将在被调用处进行代码展开,省去了参数压栈、栈帧开辟与回收,结果返回等,从而提高程序运行速度),效率很高。
-
类的内联函数也是函数。编绎器在调用一个内联函数,首先会检查参数问题,保证调用正确,像对待真正函数一样,消除了隐患及局限性。内联函数相比宏函数来说,在代码展开时,会做安全检查或自动类型转换(同普通函数),而宏定义则不会。
-
inline可以作为类的成员函数。在类中声明同时定义的成员函数,自动转化为内联函数,因此内联函数可以访问类的成员变量,宏定义则不能。
-
内联函数在运行时可调试,而宏定义不可以。
缺点:
- 代码膨胀。内联是以代码膨胀(复制)为代价,消除函数调用带来的开销。如果执行函数体内代码的时间,相比于函数调用的开销较大(比如函数体内有循环),那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。这种情况编译器可能会自动把它作为非内联函数处理。
- inline 函数无法随着函数库升级而升级。inline函数的改变需要重新编译,不像 non-inline 可以直接链接。
- 是否内联,程序员不可控。内联函数只是对编译器的建议,是否对函数内联,决定权在于编译器。
内联函数一般可以:
-
加快程序的执行速度;
-
可能减小可执行文件的大小;
-
可能增加可执行文件的大小;
-
可能降低执行速度。
1和3很好理解,在编译时期内联函数能将代码直接写入其被调用的地方,这样就减少了入栈出栈的时间消耗,但是如果调用内联函数的地方过多,代码量也会随之增加,增加了可执行文件的大小。
2为什么正确呢?是因为如果调用普通函数的话编译器可能会产生更多的代码来实现压、出寄存器的代码,对于简单的内联函数会这样。但如果优化器能顺序集成消除大量冗余代码的话,对大函数也同样适用。
4呢?如果可执行文件过大,会频繁的出现内存的换入换出操作,会使执行速度下降。
虚函数(virtual)可以是内联函数(inline)吗?什么是虚函数?
- 虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联。
- 内联是在编译器建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。
inline virtual
唯一可以内联的时候是:编译器知道所调用的对象是哪个类(如Base::who()
),这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。
虚函数内联使用
#include <iostream>
using namespace std;
class Base
{
public:inline virtual void who(){cout << "I am Base\n";}virtual ~Base() {}
};
class Derived : public Base
{
public:inline void who() // 不写inline时隐式内联{cout << "I am Derived\n";}
};int main()
{// 此处的虚函数 who(),是通过类(Base)的具体对象(b)来调用的,编译期间就能确定了,所以它可以是内联的,但最终是否内联取决于编译器。 Base b;b.who();// 此处的虚函数是通过指针调用的,呈现多态性,需要在运行时期间才能确定,所以不能为内联。 Base *ptr = new Derived();ptr->who();// 因为Base有虚析构函数(virtual ~Base() {}),所以 delete 时,会先调用派生类(Derived)析构函数,再调用基类(Base)析构函数,防止内存泄漏。delete ptr;ptr = nullptr;system("pause");return 0;
}
inline 与 typedef 与 define
typedef
- 类型重命名可以写在函数外部,同样也可以函数内部,它们的作用域不同,可以提高代码的可读性
- typedef 可以分别为基本类型重命名、指针类型重命名、结构体类型重命名和函数指针类型重命名
- typedef 是关键字,在编译时处理,有类型检查功能,用来给一个已经存在的类型一个别名,但不能在一个函数定义里面使用 typedef 。
define
- 原理:#define 作为预处理指令,在编译预处理时进行替换操作,不作正确性检查,只有在编译已被展开的源程序时才会发现可能的错误并报错。#define 不仅可以为类型取别名,还可以定义常量、变量、编译开关等。
- 作用域:#define 没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用,而 typedef 有自己的作用域。
- enum给int型常量起名字,typedef给数据类型起名字,宏定义也可以看做一种重命名
指针的操作:typedef 和 #define 在处理指针时不完全一样
#include <iostream>
#define INTPTR1 int *
typedef int * INTPTR2;using namespace std;int main()
{INTPTR1 p1, p2; // p1: int *; p2: intINTPTR2 p3, p4; // p3: int *; p4: int *int var = 1;const INTPTR1 p5 = &var; // 相当于 const int * p5; 常量指针,即不可以通过 p5 去修改 p5 指向的内容,但是 p5 可以指向其他内容。const INTPTR2 p6 = &var; // 相当于 int * const p6; 指针常量,不可使 p6 再指向其他内容。return 0;
}
C++ 中推荐使用 inline 代替 #define 声明函数
- C++ 中使用 inline 定义内联函数(C 语言中一般是使用 #define 定义宏函数)
- 宏函数是简单的文本替换,不是真正的传参数,如果不注意运算顺序很容易出错,C++ 使用 inline 定义内联函数,比定义宏函数可靠,inline 定义的内联函数是真正的传递参数,C++ 中 inline 可用于常规函数也可用于类方法
- 宏函数的一个优点是无类型,可用于任意类型,运算都是有意义的,在 C++ 中可创建内联函数模板实现这个功能
相关文章:

C++语言特性——关键字(static、volatile、extern、const、mutable、inline)
注意: 本内容为摘抄网上的学习资料,作为个人笔记使用,如有侵权, 立刻删除。 C语言特性 1.关键字 (1)static static全局变量和普通全局变量 面试高频指数:★★★☆☆ 相同点: 存储方式&…...

在Ubuntu 16.04上安装和配置VNC的方法
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 ###介绍 VNC,即“Virtual Network Computing”,是一种连接系统,允许您使用键盘和鼠标与远程服务器上…...

@RequestBody注解的使用及源码解析
前言 RequestBody 注解是我们进行JavaEE开发,最常见的几个注解之一,这篇博文我们以案例和源码相结合,帮助大家更好的了解 RequestBody 注解 使用案例 1.自定义实体类 Data NoArgsConstructor AllArgsConstructor public class User {priv…...

linux 服务器数据备份 和 mysql 数据迁移
查看域名ip 查看程序所处文件位置 list open files 1、 lsof -i :port 查看端口获取进程 pid 2、lsof -i pid 1、scp 下载服务器文件到本地 security copy protocol 2、导出服务器 mysql 数据库(表)到本地 mysqldump是MySQL自带的一个实用程序&…...

安防视频监控/云存储/视频汇聚EasyCVR平台播放设备录像不稳定,是什么原因?
安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,EasyCVR基于云边端一体化架构,具有强大的数据接入、处理及分发能力,可提供7*24小时实时高清视频监控、云端录像、云存储、录像检索与回看、智能告警…...

S32V234平台开发(一)快速使用
快速使用 准备供电复位选择串口通信启动选择显示登陆系统 准备供电 s32v234可以使用两种电源供电 一种是左边电源端子,一种是右边电源适配器(12V 3A) 注意:不要同时使用两种电源同时供电 复位选择 Pressing POR RESET pulls active low EXT_POR signal on S32V2…...

C# 如何防止反编译?C#程序加密混淆保护方法大全
在C#开发中,由于.NET程序集(assemblies)是基于中间语言(Intermediate Language, IL)编译的,这些程序集可以被反编译回接近原始源代码的形式。为了保护代码不被轻易反编译,开发者可以采取以下几种…...

企业数字化转型中的低代码开发平台应用:释放创新潜能
随着信息技术的飞速发展,企业数字化转型已成为行业趋势。在这场转型浪潮中,低代码开发平台以其独特的优势,成为众多企业实现快速迭代、高效创新的得力助手。本文将深入探讨低代码开发平台在企业数字化转型中的应用,以及如何帮助企…...

因为目录问题开通的另外一个网站的美化过程
起 其实也不完全是目录,是查找问题过程中看到别人的界面好好看,而且确实那个目录很吸引我…… 然后我在csdn看了半天,看到一个有目录的我赶紧换上,结果并不能显示。而且把原来黑色模式的给搞没有了——它居然要vip了……所以………...

RedHat运维-Ansible自动化运维基础24-寻找问题常用模块
1. ansible.builtin.uri模块的作用是____________________________; 2. ansible.builtin.uri模块的作用是____________________________; 3. ansible.builtin.uri模块的作用是____________________________; 4. 试着用ansible.builtin.uri模块…...

windows USB 设备驱动开发-USB带宽
本文讨论如何仔细管理 USB 带宽的指导。 每个 USB 客户端驱动程序都有责任最大程度地减少其使用的 USB 带宽,并尽快将未使用的带宽返回到可用带宽池。 在这里,我们认为USB 2.0 的速度是480Mbps、12Mbps、1.5Mbps,这分别对应高速、全速、低速…...

哪有什么「历史的垃圾时间」,有的只是你对自己的不诚实
时间不会服从任何人的管理,它只会自顾自地流逝。— 李笑来《把时间当作朋友》 hi,欢迎来到我的杂货铺。 最近有个概念火了,叫做「历史的垃圾时间」。 看了下相关的文章,大概是在宣扬奥地利派经济学家米赛斯关于历史的一段论述&a…...

全志A527 T527 android13支持usb摄像头
1.前言 我们发现usb摄像头在A527 android13上面并不能正常使用,需要支持相关的摄像头。 2.系统节点查看 我们查看系统是否有相关的节点生成,发现/dev/video相关的节点已经生成了。并没有问题,拔插正常。 3.这里我们需要查看系统层是否支持相关的相机, 我们使用命令进行…...

邦芒贴士:做到这8点工作生活中才能少犯错
我们之所以需要重点关注这些问题,就是为了确保自身利益能够最大化。如果大家在平日活动里能避免犯下这些错误,就会发现自己的工作效率将会大幅提升,更不用提生活也会变得愉快了很多。 大家如果曾经从建立待办事项列表中获得了很多好处的话&a…...

代码随想录算法训练营第7天
454.四数相加 题目链接:454. 四数相加 II - 力扣(LeetCode) 视频/文档链接:代码随想录 (programmercarl.com) 第一想法 遍历数组num1,num2,计算其和出现的数量,放入map集合中,键为和࿰…...

苹果开发者取消自动续费
文档:https://support.apple.com/zh-cn/118428 如果没有找到订阅,那就是账号不对 取消订阅后,就不会自动续费了,如果不放心,可以把付款绑定的方式也取消...

Phospho:LLM应用的文本分析利器
今天向大家介绍phospho文本分析平台,专门为大型语言模型(LLM)应用程序设计。它可以帮助开发者从用户或应用程序的文本消息中检测问题、提取洞见、收集用户反馈,并衡量成功。作为一个开源项目,phospho允许开发者查看和修…...

微深节能 料场堆取料无人操作系统 格雷母线
随着工业自动化的快速发展,料场堆取料作业正逐步向无人化、智能化转型。格雷母线高精度位移检测系统在料场堆取料无人操作系统中的应用,成为这一转型过程中的重要技术突破。本文将详细介绍格雷母线及其在料场堆取料无人操作系统中的应用,并探…...

Invoice OCR
Invoice OCR 发票识别 其他类型ORC: DIPS_YTPC OCR-CSDN博客...

无菌隔离器内操作规范性的验证之气流流型验证-北京中邦兴业
无菌隔离器在制药行业的使用愈加广泛,但已有的研究更多地聚焦于设计布局、物料状态等方面,对人员操作因素的影响方面关注较少。以冻干制剂生产车间为例,设计了一系列合理的无菌隔离器内干预操作,并在操作人员实行干预操作的基础上…...

【YOLOv8系列】(一)YOLOv8介绍:实时目标检测的最新突破
目录 引言 背景与发展历程 YOLOv8架构设计 1. 改进的特征提取网络 2. 多尺度特征融合 3. 新的激活函数 4. Attention机制 模型训练与优化 性能评估 应用案例 目标检测 图像分割 图像分类 姿势估计 旋转框检测(OBB) 优势与挑战 优势&…...

如何视频提取字幕?推荐5款视频字幕提取软件
#7月份我的同事一个个消失了#,这不仅是一个话题标签,更是许多公司面临的现实写照。 在人手紧缺的夏日,如何提高工作效率成为当务之急。特别是对于需要处理视频内容的团队,一款能够快速提取字幕的软件显得尤为重要。 下面&#x…...

独孤思维:副业项目实操3天出单了
01 不要吐槽项目不行,带队老师不行。 有的人能从项目赚到钱,有的人能够跑通项目。 就意味着项目本身没错。 而推卸责任的你,不行。 远的不说,就拿图书项目为例。 为什么做得好的学员,三天就能出单。 有的为什么…...

包装器 std::function
使用前,包头文件:#include <functional> std::function 是 C标准库 中的一个通用函数包装器; 它可以储存、复制、调用任何可调用的对象,包括:函数指针、成员函数、绑定的成员函数、lambda表达式、仿函数等。 1…...

Java | Leetcode Java题解之第219题存在重复元素II
题目: 题解: class Solution {public boolean containsNearbyDuplicate(int[] nums, int k) {Set<Integer> set new HashSet<Integer>();int length nums.length;for (int i 0; i < length; i) {if (i > k) {set.remove(nums[i - …...

800 元打造家庭版 SOC 安全运营中心
今天,我们开始一系列新的文章,将从独特而全面的角度探索网络安全世界,结合安全双方:红队和蓝队。 这种方法通常称为“紫队”,集成了进攻和防御技术,以提供对威胁和安全解决方案的全面了解。 在本系列的第一篇文章中,我们将指导您完成以 100 欧元约800元左右的预算创建…...

vite项目使用qiankun构建hash路由微前端
文章目录 前言一、主应用使用react18 react-router-dom61、项目安装2、主应用中注册微应用3、主应用中设置路由和挂载子应用的组件 二、创建react18 react-router-dom6子应用1、项目安装2、修改子应用 vite.config.ts3、修改子应用 main.tsx,区分qiankun环境和独立部署环境4、…...

通过rpmbuild构建Elasticsearch-7.14.2-search-guard的RPM包
系列文章目录 rpmbuild从入门到放弃 search-guard插件使用入门手册 文章目录 系列文章目录前言一、资源准备二、spec文件1.基础信息2.%prep3.%Install4.%file5.%post6.%postun 三、成果演示1.执行构建过程图示例2.执行安装RPM包示例3.进程检查4.访问esApi 总结 前言 不管是源…...

js 图片放大镜
写购物项目的时候,需要放大图片,这里用js写了一个方法,鼠标悬浮的时候放大当前图片 这个是class写法 <!--* Descripttion: * Author: 苍狼一啸八荒惊* LastEditTime: 2024-07-10 09:41:34* LastEditors: 夜空苍狼啸 --><!DOCTYPE …...

数据模型-ER图在数据模型设计中的应用
ER图在数据模型设计中的应用 1. ER图概述:起源与发展 实体-关系图(Entity Relationship Diagram,简称ER图)起源于1970年代,由Peter Chen首次提出,作为描述数据和信息间关系的图形化语言。随着数据库技术…...