初学C++的时候,有没有想过,为什么C++支持重载,而C不支持重载呢??
其实,一个程序运行起来都要经过四步骤
预处理阶段会经过去注释,宏替换,头文件展开,条件编译...
编译阶段会生成汇编代码,会经过语法分析,词法分析,语义分析,符号汇总...(像了解详细的可以去看看 《程序员的自我修养》,在它的第二章会详细讲解)
汇编阶段会将汇编生成二进制,然后在这一阶段生成符号表
链接阶段会合并段表,符号表的汇总和重定向。
这时回到我们一开始的问题,为什么C++支持重载呢??? 就是因为通过C++可以通过函数名的修饰规则来区分,而C函数名修饰规则后,函数名都是一样的,所以不能重载。
那么有一个问题,如果有两个函数,函数名一样,参数一样,但返回值不同,这是否能构成重载呢??
当然不能,因为编译器不能够通过返回值不同来判断是否构成重载。
引用:引用不是定义一个变量,而是给已存在变量取了一个别名,编译器不会另外开辟空间,而是和变量一起共用一个空间。
引用经常和指针来对比,而引用经常用来做返回值,这时因为用引用来做返回值,可以提高效率。
#include
#include
using namespace std;
struct A
{
int a[10000];
};
A a;
// 值返回
A TestFunc1()
{
return a;
}
// 引用返回
A &TestFunc2()
{
return a;
}
void TestReturnByRefOrValue()
{
// 以值作为函数的返回值类型
size_t begin1 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc1();
size_t end1 = clock();
// 以引用作为函数的返回值类型
size_t begin2 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc2();
size_t end2 = clock();
// 计算两个函数运算完成之后的时间
cout << "TestFunc1 time:" << end1 - begin1 << endl;
cout << "TestFunc2 time:" << end2 - begin2 << endl;
}
int main()
{
TestReturnByRefOrValue();
return 0;
}
但有一个很重要的区别就是
类的6个默认成员函数:
构造函数:构造函数是一个特殊的成员函数,需要注意的是构造函数的工作是初始化对象。
而默认构造函数有三种:
ps:这三种默认构造函数不能同时存在。如果2 3 同时存在,那么当一个类时空类的时候,它调用的时候就会存在歧义。
特征如下:
在创建对象的时候,编译器会自动调用构造函数,给每个成员赋初值,这时每个成员都会去走初始化列表。
初始化列表:以一个冒号开始,接着是一个逗号分割的数据成员列表,每个“成员变量”后面跟一个放在括号中的初始值或表达式。
class A
{
A()
:_a(a)
,_b(b)
{}
private:
int _a;
int _b;
};
当然每个成员在初始化的时候只能初始化一次,但有三种必须放到初始化列表中
析构函数:与构造函数相反,析构函数是在对象销毁时自动调用析构函数,完成对对象中资源的清理工作。
特征如下:
拷贝构造函数:只有单个参数,该参数是对本类型的引用,当一个已经存在的对象初始化创建一个新对象的时候,会自动调用拷贝构造函数。
特征如下:
编译器默认生成的拷贝构造函数是值拷贝,在某些场景是不能使用的,所以需要我们去深拷贝。
C++11增加了两个默认的成员函数:
针对移动构造函数和移动赋值运算符重载有写特定的要求:
赋值运算符重载:C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有返回值类型,函数名字以及参数列表,其返回值类型与普通的函数类型。
特征如下:
我们来看一下string的赋值运算符重载,不难发现它的返回值是string&。
想一想为什么返回值会是引用呢??
参数是const T&,是因为这样可以支持左值或右值,传递引用也是为了提高效率。
explicit关键字:
构造函数不仅仅可以构造还可以初始化对象,对于单个参数或除第一个参数无默认值其余都有默认值的构造函数,还具有隐式类型的转换的作用。而explicit关键字的作用就是修饰构造函数,禁止构造函数去隐式类型的转换。
static成员:
用static修饰的成员变量叫做静态成员变量,用static修饰的成员函数,叫做静态成员函数。静态成员变量一定要在类外进行初始化。
class A
{
static int _a;
};
int A::_a = 1;
特征如下: