C++学习(一)
学过C++的人都知道,C++是一种纷繁复杂的语言,所涉及的知识点非常零碎且多,但是又是各大招聘公司非常看重的语言,因此在此笔者就趁着兴致,尽量详细的向大家总结一些C++中一些相关的知识。
1.内联函数(inline)
内联函数其实就是一个真正的函数,其具备了普通函数的一切形式要素,只是与普通函数在调用时有些区别。当我们在程序中调用一个普通函数时,必须要将程序执行的顺序转移到该函数所存放在内存中的某个地址,且将该函数的程序内容执行完后,再返回到当初转去执行该函数前的地方。这种转移操作要求在转去执行前要保存现场并记忆执行的地址,转回后要恢复现场,也就是我们的入栈出栈操作,并按原来保存地址继续执行。因此,函数调用有一定的时间开销,也就将影响程序执行效率。
但是如果是调用内联函数,编译器不会去做这些操作,而是将该函数的代码,整段复制到当前的位置,这可能就有点类似我们的宏替换了,确实,内联函数这点与宏定义有些像,但是其比宏更加有优势,因为内联函数相比宏没有付出任何额外代价,但是更加安全,而且还有严格的参数类型检查。
由于内联函数不用做一些跳转,因此其加快了程序的执行效率,但是由于其每次都复制了一部分函数代码,因此其也牺牲了一些内存空间。因此对于内联函数的使用,我们有以下几点要求。
inline函数使用情况
-
归函数不能是内联函数。
-
函数内的代码尽量少,不宜超过5行,更不能有循环语句或者switch语句。
-
该函数不断被重复调用。
-
在一个文件中定义的内联函数不能在另一个头文件中使用,他们通常放在头文件中共享。
-
一般,类的内部定义了函数体的函数,被默认为内联函数。
另外我们需要注意的一点是inline函数的关键字inline必须与函数定义体放在一起才能使函数成为内联,仅将inline放在函数声明前面不起任何作用。
2.const关键字
有关const的相关知识在我们程序中经常的出现,在此我就对其主要功能进行一个总结和介绍。
const顾名思义就是常量,但是我们最好的叫法是只读变量,const对于普通变量的修饰很简单,我们就只介绍下其对指针的修饰情况。
(1)const修饰指针的用法
int b = 500;
const int* a = &b; (1)
int const * a = &b; (2)
int* const a =&b; (3)
const int* const a =&b; (4)
以上四种情况基本囊括了const对指针修饰的各种方式,有关其修饰的对象到底是指针还是指针指向的内容,我们这里有个方法,就是去掉类型标识符,看const后面最靠近哪个就是修饰哪个,比方说
const int* a = &b去掉int标识符后变为const *a =&b;
此时离const最近的就是*了,因此此时的const修饰的就是我们a指针所指向的内容了。也就是说此时指针指向的内容只读,但指针可以改变。据此我们就很容易知道另外三种情况const修饰的对象了。
情况2:与情况1一模一样。
情况3:去掉int后离const最近的是a,因此const修饰的就是a这个指针了。
情况4:去掉int,很容易知道前一个const修饰*,后一个const修饰a,此时指针和指针所指向的内容都不可更改。
需要注意的是const修饰变量时,必须要进行初始化,对于类的成员变量,又不能在类定义的时候进行初始化,应该在构造函数中初始化。
(2)const修饰函数参数
const修饰函数参数时只能修饰输入参数,目的是防止意外改动传递的指针,例如:
void copy(char *des,const char *scr);
函数是将第二个指针内容复制到第一个指针内容,但是在程序中使用const禁止修改scr指针的内容,从而保护源数据。
(3)const修饰函数返回值
这个其实类似与我们的const修饰变量,无非就是对函数返回值的限定,比方说:
const char* getString(void);
我们依然可以用前面的去除类型标识符法,来判定const修饰对象,在此就不做深入说明了。
(4)const修饰类的成员函数
经常看见在类的成员函数声明后面加了一个const,一直不知道是什么意思,现在终于明白了,这表示该函数不可以修改类的数据成员。举一个简单的例子,我们有一个类声明如下:
class A
{
public:
void setValue(int v)
{
value = v;
}
int getValue() const
{
return value;
}
private:
int value;
//mutable intchange;
}
在这个类中,我们有两个函数,第一个函数setValue修改了成员变量value的值,因此不能指定为const成员函数,而getValue没有修改成员变量的值,因此我们应该将其指定为const成员函数,这样可提高程序的可靠性,因此在一个类中,任何不会修改数据成员的函数都应该声明为const类型,如果在编写const成员函数时不小心修改了成员变量,或者调用了其它非const成员函数,编译器会报错,无疑提高了程序的可读性。这就是const成员函数的功能。
需要补充一点,对于const成员函数,只能是非静态函数,如果非要修改一个类的成员变量,可以在要修改的成员加上mutable关键字修饰,这之后,就可以在const成员函数中修改他了。例如上面的那个类中,成员函数中可以修改change变量的值。
3.指针数组和数组指针的介绍
这两个概念经常遇到,也经常容易搞混,所以也在此总结一下。有关这两个名词,其实英文的解释会让你更加明了。
指针数组:array of pointers,
数组指针:a pointer to an array,
其实中文也是可以理解的,指针数组,结果还是一个数组,只不过其元素都是指针,而数组指针,定位的在指针,表示一个指向数组的指针,借用网上的一张图的表示我们就可以更加清楚的理解这两个概念了。
(1)int* p1[10]; // 指针数组(2)int (*p2)[10]; //数组指针
前面一个就是我们的指针数组了,其每个元素都是指针,后面一个就是数组指针,其指向一个包含十个元素的数组。
下面是截的网上一个程序,觉得可以看看,具体分析都有注释,我们可以不看注释自己分析结果加深对指针的了解。
除了指针数组和数组指针的讨论,类似的还有函数指针和指针函数,在此我也做一个简单的比较,
(1)函数指针:
其落点在指针,因此其是一个指针变量,我们可以采用下面的方式来声明一个函数指针:
类型说明符 (*函数名)(参数)
例如:
int (*f)(int ,int);
在程序代码中我们就可以通过两种方式把函数的地址赋值给函数指针,如下:
(1)f = fun;
(2)f = &fun;
函数调用时我们也有两种方式,比方说我们要调用上面的fun函数,采用函数指针的方式可以是:
(1)x = f();
(2)x = (*f)();
具体使用哪种方式依程序员自己的偏好了。
(2)指针函数:
其落点在函数,因此其本质就是一个函数。其声明方式为:
类型标识符 *函数名(参数表)
例如:
int *f(int, int);
指针函数是一个函数,只是其返回值为一个指针变量,调用指针函数时,其返回值必须赋给同类的指针变量,否则必须加强制类型转换。
以上就是有关C/C++的一些知识的冰山一角,我将在后面陆续介绍更多的相关知识。