本文主要描述1:const修饰符,2:模版相关内容,3:指针和引用的区别,4:内联与预定义,5:虚表相关内容。
一:const修饰符
const修饰符可以修饰函数,函数参数,函数返回值,变量等。
(1)修饰函数 int function() const
const修饰函数表明在函数内不能修改对象数据成员且不能调用非const函数。因为在非const内部能修改数据成员,而const修饰的函数是不能改变的,因此是不能调用的。
(2)修饰函数参数 int function(const int& value)
防止传入的参数代表的内容在函数体内被改变,但仅对指针和引用有意义。如果是按值传递,传给参数的是实参的副本,即使改变形参,实参也不会受影响。
const修饰指针时,代表在函数体内不能修改该指针所指的内容,起到保护作用,const指针能接受非const和const指针,而非const指针只能接受非const指针。
const修饰引用时,按值传递时拷贝存在空间和时间的浪费,如果按引用传递能解决这个问题,但是存在安全隐患,这时候可以用const来保护。
(3)const修饰函数返回值
也是用来修饰返回的指针或引用,保证内容不被修改。归根结底是使得函数调用表达式不能作为左值。
int& get(); === get() = 2;
const int& get();
二:模版相关内容
模版是泛型编程的公式。我们可以用模版来定义函数和类。
函数模版
template ret-type func-name(parameter list)
inline T const& Max(T const& a, T const& b)
{
return a < b ? b : a;
}
int I = 10, j = 20; cout << Max(i, j)<<endl;
string a = "hello", b = "world"; cout<<Max(a,b)<<endl;
类模版
template class class-name{
.
.
.
}
> template<class T> class Stack{
> public:
> void pop();
> private:
> vector<T> elems; };
>
> template <class T> void Stack<T>::pop() {
> if (elems.empty()){
> throw out_of_range("stack<>::pop(): empty stack");
> }
> elems.pop_back(); }
…
模版特化
> template <> void Stack<int>::pop() {
> if (elems.empty()){
> throw out_of_range("stack<int>::pop(): empty stack");
> }
> elems.pop_back(); }
模版特化分为全特化和偏特化,全特化是所有类型都指明,偏特化是指部分知名。调用的顺序是全特化类>偏特化类>主版本模版类。
三:指针和引用的区别
(1)引用
int m;
int &n = m;
n相当于是m的别称,对n的操作就是对m的操作,n就是m它自己。
引用的规则
1)引用被创建的同时必须被初始化(指针则可以在任何地方初始化)
2)不能有NULL引用,引用必须与合法的存储单元关联(指针可以为NULL)
3)一旦引用呗初始化,则不能改变引用关系(指针可以随时改变所指的对象)
引用的主要功能是传递函数的参数和返回值。
C++语言中参数和返回值的传递方式有三种,值传递,指针传递和引用传递。
程序为指针变量分配内存区域,而引用不分配内存区域。
指针可以被重新赋值以指向另一个不同的对象,但引用总是窒息那个初始化时被指定的对象,以后不能改变。
sizeof(引用)得到所指向内容的大小,sizeof(指针)得到指针本身的大小。
四:内联和宏定义
#define Max(a,b) ((a)>(b)?(a)>(b))
inline int Max(int a, int b) {return a>b?a:b;}
内联的好处:
(1)内联能调试
(2)可进行类型安全检查或自动类型转换。
(3)可访问成员变量。
(4)内联函数提高了效率(省去调用汇编代码,call和ret等)
如果代码长,使用内联会导致内存消耗代价比较大,如果内联代码内出现循环,那么执行函数体内的代码的时间要比函数调用的开销大。
五:虚表相关内容
在C++语言中,每个有虚函数的类或者虚继承的子类,编译器都会为它生成一个虚拟函数表(简称:虚表),表中的每一个元素都指向一个虚函数的地址。(注意:虚表是从属于类的)
此外,编译器会为包含虚函数的类加上一个成员变量,是一个指向该虚函数表的指针(常被称为vptr),每一个由此类别派生出来的类,都有这么一个vptr。虚表指针是从属于对象的。也就是说,如果一个类含有虚表,则该类的所有对象都会含有一个虚表指针,并且该虚表指针指向同一个虚表。
虚表的内容是依据类中的虚函数声明次序–填入函数指针。派生类别会继承基础类别的虚表(以及所有其他可以继承的成员),当我们在派生类中改写虚函数时,虚表就受了影响;表中的元素所指的函数地址将不再是基类的函数地址,而是派生类的函数地址。