标签:
本文摘自:Thinking in C++ Vol.1 (添加部分C++ primer内容。待续...)
安装c/c++的帮助文档:
yum install man-pages libstdc++-docs
int *x, y;
中x是指针,y是整型变量。cin>>a>>b>>c>>d>>e>>f>>g;
则a = 1 b = 5 c = 1...例如:int i{7};特点:使用花括号对变量进行赋值时,当存在丢失数据的风险时,编译器会报错:int i{3.14};是无法通过编译的,因为会丢失数据。
构造函数和默认构造函数的一些区别
默认构造函数分为两类,一类是系统自动生成的,即此时类中没有定义构造函数。第二类是类的作者写的不带参数的构造函数或者带默认参数的构造函数。调用这类构造函数的标准语法是
ClassName objectname;
(注意这里是不带括号的)。其他的构造函数都是带有非默认参数的,这些构造函数的调用需要加上参数,而这类情况是比较常见的。在定义一个类的时候不能使用这种方式:ClassName object();
即在对象名后加上一个空括号,在任何地方这种语法都会被编译器认为是声明一个没有参数且返回值是ClassName的函数(参考)。MyClass c1;//表示使用不带参数的构造函数,或者有默认参数值的构造函数。 MyClass c2();//不会调用无参构造函数,各种情况下该处是声明一个返回值为MyClass类型的函数而已 MyClass c3(1);//调用参数为int的构造函数 /*---------------对于new关键字加括号和不加括号的区别--- 1.对于自定义类型来说没有区别,都是使用默认构造函数 2.对于内置类型来说加括号会初始化 */
返回值优化
在函数内部:
return ClassName(paramaters);
和ClassName tmp(paramaters);
return tem;
有着不同的含义,前者将直接在返回值地址上创建对像,只会调用一个构造函数。而后者会创建一个局部变量然后再返回,此时的开销要比前者大。这就是返回值优化。
聚合(aggregation)或组合:被认为是“有一个” , 就像“汽车有发动机”。
inheritance(继承):reusing the interface (接口的重用) 消耗较组合大。
当构建一个新类时你应该首先考虑组合(而不是继承),因为组合比继承更简单更灵活。
你有两种方法使你继承的类和基类不同:
使用关键字virtual声明你想让一个函数具有晚绑定的属性。
我们把处理继承类就像处理其基类的过程称为向上类型转换(upcasting)。
我们有两种主要的创建对象的方法:
#include <iostream.h>
means#include <iostream>
using namespace std;
八进制和十六进制:
cout << "in octal: " << oct << 15 << endl;
cout << "in hex: " << hex << 15 << endl;
容器 vector:
容器是模板,意味着它可以高效的应用于不同的类型。
vector就是一个容器(其结构类似于数组,左边是起始,右边是尾部)故使用push_back()添加新的数据。
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
using namespace std;
int main()
{
ifstream in("test.txt");
string str;
vector< string > strvec;
//while(getline(in, str)) strvec.push_back(strvec); // 每次读一行,下面这行代码,每次读两个空格之间的字符串,
while( in >> str )strvec.push_back(str); //以空格作为间隔读取数据,可能同时输出单词和符号,例如 .hello,
for(int i = 0 ; i <strvec.size();i++)cout<<i<<‘:‘<<strvec[i]<<endl;
return 0;
}
如果定义了一个数组而没有初始化,则编译器不会初始化数组。但若给出少于数组元素个数的初始化数据,则余下的数组元素会被初始化为0。故int b[n] = {0} ; 是将所有数组元素初始化为0 的简洁方法。
引用的特点:
强制转换:c++比c多了一种转换的语法int(data),在c中只能写成(int)data。
强制类型转换:
c++的类型检查比c++严格:
int i = 10;
void *vp = &i;//c与c++均可
int *ip = vp;//c中可用,但在c++中不允许,在c++中不允许将void指针直接赋予其他类型的指针。
c++中不允许调用未事先声明的函数,但c可以。 c++中有显式运算符,例如:&&可以表达为 and
使用函数指针调用函数的正规语法:(*funp)(data),但大部分编译器允许程序员写作funp(data) ,但这只是一种简写的方式。
下面的#和##只能用于宏定义中:
#将变量或表达式转化为字符串。当你在宏变量前加上 # ,预处理器会把宏参数转换为字符串。 标志粘贴:##将两个标识符连接从而形成一个新的标识符。
在标准头文件中你可以发现assert(),这是一个方便的debug宏。当你使用assert()时,你提供一个参数,也就是一个你认为为真的等式(断言)。预处理器会生成一些代码测试这个等式,如果断言是假,程序会停止运行并给出断言所处的位置。 完成测试之后在代码的开始加上 #define ndebug 则可使assert()失效,从而提高效率。
函数的地址可以使用其函数名表示。 当然也可以使用更明确的方法,使用取址符号, &fun().
int main()
{
int (*fp)(void); //定义函数指针
pr();
fp = pr;
fp(); //这两个使用方法均是正确的,但后者更规范,fp() 这种定义是编译器提供的。
(*fp)(); //
}
C++标准规定字符串内存的分配允许但不要求使用引用计数。但无论是否使用引用计数,类的实现对用户而言必须是透明的。
引用计数:
在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。使用引用计数的一个优点是可以实现写时复制,这样可以节省时间和内存。但在多线程编程中几乎无法使用引用计数技术。
字符串"\1234"所表示的是两个字符:\123为123所对应的字符unicode值,而4又是另一个字符的Unicode值(或者ASCII)。
+--------+-----------+----------+ | 前缀 | 含义 | 类型 | +--------+-----------+----------+ | u | Unicode16 | char16_t | +--------+-----------+----------+ | U | Unicode32 | char32_t | +--------+-----------+----------+ | L | 宽字符 | wchar_t | +--------+-----------+----------+ | u8 | UTF-8 | char | +--------+-----------+----------+
第四章的部分内容: ::(作用域解析运算符):
指定所定义的函数所属的范围。stash::link::add() 说明定义的add()函数属于stash中的link结构。此操作符只用于类或结构,不能用于他们的实例,因为这是没有意义的,只用改变类或结构才会改变他们的实例(类和结构像模板,而实例相当于他们的拷贝,只有模板变量,拷贝才会变)。如果在变量或函数之前使用 ::说明函数或变量时是全局变量和函数,不是本类或结构体中的与全局变量同名的函数和变量。
c++访问控制:
构造函数与析构函数均为public成员,因为析构函数与构造函数均由系统自动调用,而调用的方式是在对象定义处与包含对象的右括号处由编译器自动插入调用构造与析构函数的语句。此时这两个函数相当于在对象的外部执行,其必须为public。
可以通过在结构中声明友元实现让一个非成员函数更改某个结构中的成员。在所有关系中一个非常重要的规则是“谁能访问我的私有成员?
构造函数:
与类的名字相同,但没有返回值 。在创建对象时,由编译器自动的调用。编译器会在对象的定义处插入构造函数的调用行,编译器会隐含的向构造函数传递一个参数,即本对象的内存地址。 构造函数没有返回值是因为构造函数是由系统自动调用的,如果为其添加返回值,系统必须自动处理返回值,而这样做没有意义。
默认构造函数:
可以不显式的提供参数的构造函数,例如类中定义的无参构造函数和参数都有默认参数的构造函数,当然了还有系统自动生成的。当类中没有显式的定义构造函数,系统会生成一个默认的构造函数,但这个默认构造函数不会对对象中的数据做明确的初始化。
在析构函数内部使用exit函数是非常危险的,因为程序从main中退出时有时也是调用exit函数,如果在析构函数中使用exit函数将会造成死循环:例如程序从main中退出,系统会调用exit函数,这时系统会调用对象的析构,如果析构函数中存在exit函数那么系统会去终止main函数,而main中打exit触发后会再次去执行对象的析构函数,这样就形成了死循环。
析构函数:
析构函数与类的名字相同但在前面添加 ~ ,析构函数没有参数表(有参数表也没意义,因为析构函数由系统自动调用,有参数表可以完成的动作,没有参数表一样可以完成,有还是没有参数对析构函数而言是一样的),且析构函数由编译器自动调用。析构函数自动调用的唯一根据是包含这个对象的右括号。
因为析构函数与构造函数均由系统自动调用,而调用的方式是在对象定义处与包含对象的右括号处由编译器自动插入调用析构与构造函数的调用语句。此时这两个函数相当于在对象的外部执行,其必须为public。
析构函数的调用顺序和构造函数的调用顺序相反。
局部跳转(goto)会可能触发析构函数(只要goto跳出了对象的作用域)。非局部跳转不会触发析构,例如:setjmp()和longjmp。构造函数与析构函数均为public成员。
c++中对象的定义和初始化是集为一体的:对象的创建和初始化必须同时完成,否则无法通过编译。一般编译器会检查是否在条件语句中定义了对象。 因为在条件语句中的对象可能没有被初始化:例如:if(*)static x x; if语句很可能因为假而被跳过,故对象x只是被分配了内存,但没有被初始化,此系统会报错或警告。
重载:
相同的名字但不同的参数表。不能使用返回值实现重载,因为很多时候我们使用了一个函数但忽略它的返回值。一般而言编译器内部实现重载的方法是使用参数列表来标识每一个函数,例如一个函数int print(float flt)在编译器内部可能表示为_print_float()。
union:
同一片内存空间,当选择联合中不同的成员时,会对这片内存做不同的解释。
匿名联合:
没有名字的联合,例如:
union{
float f;
double d;
int i;
};
在使用这种联合时,不需要联合的名字就可以使用其中的变量,例如直接对i赋值:i=9; 可以用作浮点数的相等比较
占位符参数:
声明:void f(int x , int = 0 , float flt = 1);//默认参数只能存在于函数声明中。
定义:void f(int x , int , float flt ){}
调用:调用含有占位符参数的函数,必须为占位符参数提供一个参数,而且这个参数要与占位符类型一致。
函数的声明中 int fun(); 在c++与c中的含义是不同的,c中意味着函数的参数是任意的,类型任意,参数也任意。但在c++中表示没有参数。
static在不同范围的两种意思(这些规则对对象而言一样适用):
const与volatile:
c++中与c中的const意义不同。在c中会为const变量分配内存空间,在c++中不一定会这样。在c++中const变量可能并不存在内存中,因为在编译过程中编译器可能直接将其优化而消失。
volitile 与const相反,volatile通知编译器不要优化某个变量。
位运算符 & | ~ ^(异或) << >>
注意:
所有的位运算都是在寄存器中执行的并没有在变量的内存空间有所体现。那么为了对某个变量进行位操作,必须进行赋值操作。例如 i = i>>2 ;
所有的二元运算符都可以和等号相结合如: a += 3 ; b>>=2; ~是一元运算符,不能与等号结合。
逗号运算符:
逗号运算符是所有运算符中优先级最低的。
int main()
{
int a1 , a2 , b=2 , c=3 , d=4;
a1 = (b++,c++,d++);
a2 = b++ , c++ , d++;//赋值运算符 ‘ = ‘ 的优先级高于逗号故先赋值
}
逗号运算符用于分隔表达式,而逗号运算表达式的值是最后一个表达式的值。上面a1的值为4整个表达式的值是最后一个即d++ 。 a2的值为2 ,等号的优先级要高于逗号运算符。
c++中的显式转换:
与c不同,c++中结构体的名字可以直接用来定义新的变量。
例如:定义struct s{};
在c中定义变量时需要使用:struct s vs;
在c++中可以直接使用: s vs ;
关键字this产生本结构体的地址。
java中不允许局部变量与全局变量同名,但c++可以。
c中可以使用宏定义,例如:#define pi 3.1415
在c++中使用const替代 常量的宏定义,这样可以增加程序的安全系数。
c++中cosnt默认为内部连接 ,而在c中cosnt默认为外部连接。
书中说编译器无法获得内存中的数据,这只是对某些编译器成立,在vs2013中下面的代码1无法通过编译。说明vs2013的编译器无法在编译时获得array1[1]中的数据。但在g++编译器中代码1可以通过编译并且输出为8 。 //代码1
int array1[] = {1, 2, 3, 4};
int array2[array1[1]];
提示:error c2133: ‘array2‘ : unknown size 在vs2013中无法通过编译,
//代码2
cout<<sizeof(array2);
int b = 9;
char c[b];
提示:error c2133: ‘c‘ : unknown size
//代码3
const int b = 9;
char c[b];
代码3可以通过编译,说明编译器对b做了优化(常量折叠)。
c中和c++中对const变量的定义有本质的差别:
c++中使用类似c中使用指针的方法改变const变量的行为没有定义(未定义行为),也就是更改结果与编译器实现有关。
例如:
代码1: c++
#include<iostream>
using namespace std;
#define pr(x) (cout<<#x##" = " <<x<<endl);
int main()
{
volatile const int m = 9;
pr(m)
int *pint =(int *) &m;
*pint = 6;
pr(m)
pr(*pint)
system("pause");
}
代码2: c++
#include<iostream>
using namespace std;
#define pr(x) (cout<<#x##" = " <<x<<endl);
int main()
{
const int m = 9;
//不一定开辟空间
pr(m)
//强迫编译器为常量开辟空间
int *pint =(int *) &m;
*pint = 6;
pr(m)
pr(*pint)
system("pause");
}
代码3: c
#include<stdio.h>
using namespace std;
#define pr(x) {printf(#x);printf("=") ; printf("%d\n" , x);}
int main()
{
const int m = 9;
//c编译器一定为常量开辟空间
pr(m)
int *pint =(int *) &m;
*pint = 6;
pr(m)
pr(*pint)
system("pause");
}
m = 9 m = 6 *pint = 6
m = 9 m = 9 *pint = 6
m = 9 m = 6 *pint = 6
c++中的常量是编译期间的一个定值,故编译器没必要为这个常量分配内存,而且const常量没有像字符串常量那样被分配在只读存储区。而且常量的值会保存在符号表中,编译器会将局部const变量进行常量折叠。故如果强迫编译器为常量分配内存,即使在c++中改变了常量在内存中的值,我们在代码中使用的常量的值依旧不会改变,故会出现上面代码2的情况。但是如果在常量的前面添加关键字volatile,告诉编译器不要对const常量进行优化即不做常量折叠,每次使用const常量时都从内存中读取,那么就会出现代码1中的结果。c中一定会为常量分配内存,而且每次使用时都会从内存中读取,故会出现上面的代码3的结果。从上面的结果可知,const常量没有像字符串常量那样被分配在只读存储区。
参考资料:http://blog.csdn.net/heyabo/article/details/8745942
const int *pint;
int const *pint; //这两个声明的意思是相同的,pint指向一个int型常量(这个变量中的值不能变)。
int * const pint; //pint是一个常量型指针(指针内容不可变),其指向一个int型变量。
char *pchar = "hellow !"
这样的代码在技术上而言是错误的,因为赋值号的右侧是字符串而左侧却是一个指针。但编译器允许这样,编译器默认将字符串的首地址赋予指针。在pass-by-value形式的函数前添加关键字const是没意义的,因为完全没有必要,原来的数据一定不会被更改。
如果一个函数返回一个const型的对象,那么这个函数不能作为左值,因为其返回的内存空间是不能被更改的,更不可能被赋值。当一个函数返回的是一个对象而且这个对象不是const型时,这个函数可以作为左值,例如:f(x1)=f(x2),在c中是看不见这样的赋值形式的,在c中左值永远都是变量,而不可能是函数的形式(这里涉及了C++中的临时变量的概念)。如果一个函数返回的是内建类型,那么编译器不允许其作为左值。允许返回值为对象的函数作为左值可以写出链式的表达式例如:f(x).fun(y) ,其中fun( y)为f(x)返回值的一个成员函数。可以将上面的代码作为右值,这样可以简化代码。
类中的常量有两种形式:
const对象和成员函数:
const对象只能调用对应类中的const成员函数。其中cosnt成员函数的定义,必须声明和定义的时候在参数表之后函数体之前添加const关键字。如果一个成员函数被定义为const类型那么在函数体内将无法更改对象中任何数据成员(除非这个数据被被关键词mutable修饰),否则将无法通过编译。
const成员函数的声明和定义
class test
{
public:
test(int a);
void nchange(int b ) const; //const成员函数的声明
private:
const int m_a;
int m_c;
};
void test::nchange(int b )const //const成员函数的定义
{
//m_c = b;//无法通过编译
int c = b;//c 不是类中的成员数据,故可以通过编译
}
inline:
内联函数存在的理由:使用较小的空间代价获得较大的时间效率。
内联函数的函数体中不能出现循环和sewitch语句,否则编译器会自动将其转化为非内联函数。内联函数的函数名和函数体同时存在于符号表中。内联函数的函数体会嵌入调用内联函数的地方,而不会像其他函数那样使用call指令调用。
有两种情况编译器不会执行内联:
内联函数的两种实现方法: 1、使用关键字inline声明函数。 2、在类中直接定义的函数,一般不推荐这种方法,因为这样做会破坏函数可读性。
c++规定只有在类声明结束后才会对内联函数进行计算。这样可以解决向前引用,即引用声明在自己之后的函数。
在c++ 中,那些常放在头文件中的名字如常量,内联函数默认是内部链接的。注:在C中常量默认是外部链接。
在程序的代码量达到一定的程度时,全局的名称就会发生重复,此时就需要名字空间来解决这个问题:
使用关键字namespace 来定义新的名字空间:
``` namespace mylib{ //... } //这里不加分号 ```
namespace xalias = ...; //为名字空间添加别名。
匿名名字空间:
namespace{
//...
}
使用名字空间的方法:
#include "fun1.h"
using namespace std;
int main()
{
{//名字空间的声名只给出了名字,没有类型信息,故声名引入了这个名字的重载集合。
using mylib2::name;//使用声名,那么在后面使用的name都是来自mylib2中。若想使用mylib1中的name,必须完整的限定。
using namespace mylib1;
name();//这是mylib2中的name()
mylib1::name();//完整的限定才能调用mylib1中的name。
}
salute salute("china");
salute.sayhello();
// name();
}
类中的静态变量:
static int i;
。在类中的常量(注意与对像常量的区别)有两种形式:匿名枚举和const static in a。在C++11中支持非静态变量的类中初始化。在C++11类的定义中出现int i = 2;是合法的,但在较低版本的c++标准是非法的。
局部类和嵌套类:
类中的静态成员函数:
全局变量初始化的相依性:(有相依性的全局变量存在的一些问题)
对于全局变量而言初始化顺序的不同会造成程序结果的不同,然而在不同编译单元中的全局变量的初始化次序是无法控制的。
在文件1中:
extern int y; x = y + 1 ;
文件2中:
extern int x y = x + 1 ;
编译器会默认将全局未赋值的变量初始化为0,如果上面的两个文件的编译顺序不同则x和y的值也将不同。在些程序时需要注意这些情况。
如果两个关联的全局变量无法避免,那么解决上面的问题有两种技术(技术2是最常用的):
这两种方法的核心思想是相同的:位于不同文件的有关联的静态数据要么不初始化要么就一起初始化,这样就可以限定初始化的顺序。
在两个文件中定义两个相关联的int 型数据int x 和 y 为了强制化调用次序,我们定义两个函数:
- 文件1:
int &x(){static int x = 1;return x;}
- 文件2:
int &y(){static int y = 8;return y;}
在不同的文件中使用x和y时就使用这几个函数,那么变量的初始化次序只与代码有关。那么这些变量的初始化次序是可控的。
替代连接説明:
C++ 和C 在编译时函数的名字的修饰方法是不同的,故在c++中使用c库时需要说明:extern "C" float foo(...)或者extern "C" { ... }
引用就是能自动的被编译器间接引用的常量型指针。引用可以用于函数的参数表也可以用于函数的返回值。编译器会对常量进行常量折叠。
在C中允许将void 类型的指针赋予其他类型的指针,但在C++是不允许的。
如果确定不改变引用的数据,最好声名引用为常量引用,这样函数的应用范围更广。void func(const int &data);
指针引用:
int **pIntPtr;
而在改变指针内容的时侯使用的语法一般类似:*pIntPtr = ...;int &*pIntPtr;
直接使用 pIntPtr = ...
函数框架:
在C/C++中参数表的入栈顺序是由右到左。
int f(int x , char c);
int g = f(a , b);
对应的汇编类似于:
push b ;参数入栈,右到左
push a
call f() ;
add sp 4 ;清理栈中的数据
mov g , register a
对于内建类型,编译器知道类型的大小,且编译器可以将内建类型放入寄存器中进行计筭与返回。故f()的返回值在寄存器中。对于一般的函数调用,如果函数中只有内建类型,那么内存中函数框架类似于:
....栈顶|...函数参数...|返回地址|...局部变量...|栈底....
编译器对内建类型函数的调用过程:
在整个过程中,需要返回的值是在寄存器中存储的,返回过程中,将寄存器中的数据复制出即可。然而对于非内建类型而言有时寄存器无法放下这些数据。如果将f()的返回值放在局部变量中,那么当函数返回时栈指针将指向返回地址。如果此时有其他程序的中断发生那么栈指针下的空间将分配给哪些中断程序,而此时返回值就被复盖了,故这种方式行不通。所以返回值不能存放在栈中,因为重入的原因返回值也不能放在全局变量中。
为了解决这个问题,对于含有非内建类型的函数的调用,其函数框架与前者不太相同:
....栈顶|返回值地址|...函数参数...|返回地址|...局部变量...|栈底....
若B是一个类,B = f();
返回值不再是由寄存器复制到目的地,而是由f()直接使用栈中的返回值地址将值复制到目的地。
拷贝构造:
如果知道一定会使用按值传递来传递一个对像时,那么就需要定义拷贝构造否则就没有必要定义拷贝构造。
声名一个私有的拷贝构造函数就可以避免按值传递一个对像。 默认的拷贝构造就是位拷贝。
拷贝构造函数的定义类似于:在类中定义 HowMany(const HowMany &h);
位拷贝与初始化:
int main()
{
HowMany h;
h.PrintCounts();
HowMany h2 = f(h);
}
若HowMany是一个类,且其中只有默认拷贝。那么这里使用的就是按位拷贝。
当将h拷贝到函数框架中的参数表位置时不会触发类的构造函数。
但当f()执行完成之后会触发在栈中的参数表位值的对像。 故此段代码中构造函数执行类1次而析构函数执行类3次。
如果我们没有定义拷贝构造函数,那么系统会认为我们使用按位拷贝。若类中有拷贝构造函数那么由此类创建新对像时编译器会调用拷贝构造。
临时对像:
考虑到当返回非内建类型时的函数框架,如果只调用函数而不使用返回值就像 f()。因为新的函数框架中有返回值地址而这个值是在调用函数之前就压栈的,故编译器需要知道一个这样的地址。一般的情况是编译器自动生成一个临时的对像并将这个地址传递给返回值地址。
指向成员的指针:
objectPointer->*pointMember;
先读
*pointMember
这表示pointMember所指向的成员,注意pointMember是指针,而*pointMember就是成员。
object.*pointMember;
与上面的语句的意义相同。
成员数据指针的定义:
int objectclass::*pointMember = &objectclass::Member;
// 虽然所成员指针没有地址,但使用&表示取偏移量。指向成员函数的指针:
int (objectclass::*pointFunMember)(float )const = &objectclass::f;
在这里没有给出f的参数表但由成员指针的参数表可以确定所要定义的成员函数。
运算符重载只是另一种函数的调用方式。
运算符重载中参数的个数由两个因素决定:
当重载的运算符作为成员函数的时侯,当前对像
*this
已经默认作为一个参数了。故当运算符是一元的时侯,就不再需要参数类(例如++,--),而在使用时运算符在变量的左侧。还是作为成员,当运算符是两元的时侯,我们需要为运算符重载函数提供一个参数,而这个参数默认位于运算符之右。当运算符为全局时,运算符默认有几个参数,我们就应该提供几个参数,对于正号+
,我们应该提供一个参数:int &operator+(int &a)
。但当使用加号+
时我们应该提供两个参数:int operator+(int a , int b);
对于非条件运算符重载,如果其两侧的参数类型相同,则一般要将其返回类型也设置为与参数相同的类型,避免歧义的发生。
运算符重载注意:
自增和自减:
对于自加自减运算符,在C++ 中前缀和后缀的实现方法是不同的,为了不产生歧义,在没有右值的情况下 x++ 会产生一个x的临时变量拷贝。然而对于前缀++x而言,即使没有右值,其也不会产生临时变量,这点是需要注意的。系统会自动的将临时变量设置为常量型,而我们只能调用静态常量中的静态函数成员,这点需要注意。
较为少见的运算符重载:
operator->
<<
重载这个运算符时最好使用友元形式:class {... friend ostream operator<<(ostream &os ,const current_calss); ...}
指针间接引用运算符一定是成员函数,他有着额外的非典型的限制:他必须返回一个对像或对像的引用,而且这个对像也有一个指针间接运算符;或者返回一个指针被用于选择指针间接引用运算符箭头所指向的内容。这些限制主要可以表现在语法上。 P281
operator->*
P284不能重载的运算符
.
.*
成员运算符和非成员运算符 P286
赋值号的重载
C++ 中不允许存在全局的operator=,对于一个没有创建的对像而言,使用等号会触发拷贝构造函数,然而当等号左侧的对像已经存在,那么就会调用重载的赋值号等号。
MyType b
;MyType a = b
;//调用拷贝构造函数a = b
; //使用重载的运算符等号
标签:
原文地址:http://www.cnblogs.com/jiahu-Blog/p/4851045.html