以下内容结合本人的一些总结加上网上的一些资源整合,是本人工作中感悟出来的一些经验,仅供参考,如有不对,敬请指正
New 的三种用法
1、 操作符 New, 不能被重载,改写。保持原有功能。Eg: int *I = newint(5);or new int; (教科书阶段)
2、 函数 operator new(size_t size) 这是一个类似于一个函数,可被重载,也可直接使用。
Eg: int *I = operator new int;如果重载,则返回值必须为void*,第一个参数必须为size_t,传参时,第一个参数由编译器提供,所以第一个参数不需要传入。
Eg:未重载时operator new(size_t size) ;int *I = operator new int //new没有参数,因为第一个参数已经由编译器提供了。
重载为operator new(size_t size,int arg);int *I = operator new(5) int, //new带一个参数,因为size已经由编译器提供了,这里只需要提供第二个参数。编译器经常会报如下错误:operatornew不能将第二个参数从void* 转化为 int,一开始看会觉得莫名其妙,我的new哪里有第二个参数,后来发现new的第一个参数在传参时时隐藏的,这一点也比较特殊。(进阶理论阶段)
3、 placement new 使用指定的内存块来分配,不一定从堆上分配。
格式为:new(buffer) type (初始化参数表)
eg: char buf[30]= {0};
int I= new(buf) i(5);//对 I 进行初始化为5,so buf[0] == 5;
这其实是operator new的一种重载,原型为:void* operator new(size_t size,void * buffer);
目前疑问:对于class来说,new(buff) MyClass 与 new(buff) MyClass(); 之间的区别在哪里?
C/C++ Volatile的作用:
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。
假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。
1). 一个参数既可以是const还可以是volatile吗?解释为什么。
2). 一个指针可以是volatile吗?解释为什么。
3). 下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
下面是答案:
1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
总结:加了volatile关键字的变量,编译器不会对其做任何优化,每次读写都从其地址中进行。反之,编译器可能会将经常引用而不做修改的变量存在某个寄存器里,以提升性能。
该关键字主要用在以下三个地方:
1、多线程中被多个task共享的变量
2、中断服务程序中的非自动变量(差不多就是static变量)
3、硬件寄存器中
差不多反正就是不会在你预想中变化的变量就要用volatile(非单线程中)。
三种cast
Static_cast,dynamtic_cast,const_cast
1、 static_cast 基本上和强制类型转换一样。
2、 dynamtic_cast貌似是一种RTTI机制,用于运行时类型转换。一般用于检查某个类是否派生于某个基类。如果不是返回null。
3、 const_cast是就是把const变量转换成非const的,volatile转换成非volatile,注意;一般不能直接转换,这样就违反了const等修饰符的本意。具体看例子:
#include <iostream.h>
class CCTest {
public:
void setNumber( int );
void printNumber() const;
private:
int number;
};
void CCTest::setNumber( int num ) { number = num; }
void CCTest::printNumber() const {
cout < < "\nBefore: " < < number;
const_cast < CCTest * > ( this )-> number--;
cout < < "\nAfter: " < < number;
}
void main() {
CCTest X;
X.setNumber( 8 );
X.printNumber();
}
On the line containing the const_cast, the data type of the this pointer is const CCTest *. The const_cast operator changes the data type of the this pointer to CCTest *, allowing the member number to be modified. The cast lasts only for the remainder of the line on which it appears.
You cannot use the const_cast operator to directly override a constant variable 's constant status
运算符的重载:
当重载为成员函数时,第一个参数为隐藏参数,eg:单目运算符没有形参,双目只有一个形参,三目的有两个形参。以“+”为例a+b == a.operator+(b) == operator(this,b)
当重载为友元函数时,没有隐藏参数,都是运算符实际拥有的参数。以“+”为例:
a+b ==operator+(a,b)
tip:给重载的运算符添加合适的返回类型,可以使其支持链式表达
eg:declare:MyClass& operator+(MyClass&a,MyClass &b)
MyClass a,b,c,d;
a = b+c+d ==
tmp = operator+(b,c)
tmp = operator+(tmp,d)
a = tmp;
运算符的重载:
当重载为成员函数时,第一个参数为隐藏参数,eg:单目运算符没有形参,双目只有一个形参,三目的有两个形参。以“+”为例a+b == a.operator+(b) == operator(this,b)
当重载为友元函数时,没有隐藏参数,都是运算符实际拥有的参数。以“+”为例:
a+b ==operator+(a,b)
tip:给重载的运算符添加合适的返回类型,可以使其支持链式表达
eg:declare:MyClass& operator+(MyClass&a,MyClass &b)
MyClass a,b,c,d;
a = b+c+d ==
tmp = operator+(b,c)
tmp = operator+(tmp,d)
a = tmp;
总结:运算符的重载就是函数重载的扩展实现。将每个可重载的运算符看作一种函数的重载,函数重载根据类型的不同进行重载。一般双目运算符重载比较多,以其友元为例,第一个参数为运算符左边的参数,第二个为右边的。成员函数双目重载只有一个形参,为运算符右边的参数,左边的为this。
有一点说明:不能重载形参全是基本类型的运算符
Eg:int operator+ (int i1,int i2) 这个函数不可能为成员函数,因为形参太多,应该只有一个,所以它必定是全局范围内的友元函数,既然是全局范围内的,那么这个函数就会修改所有对于两个整形之间的加法。这个加法可能是正常加法,也可能是printf()一句话,或者让你当机。全看这个重载函数的实现。如此一来就无法控制对于基本类型的运算规则。所以C++不允许这样加载形参全是基本类型的运算符。编译器会报错:“operator+”至少要有一个类 类型的形参。
对于重定向符“>>”“<<”的重载
由于C++入门教程,经常有cin>>str cout<<“hello world”<<endl;之类的语句,让我们有些忘记了>> ,<<并不是cin cout所专有的,他即是最基本的功能是位运算的左移右移运算符。标题称之为重定向符,是因为我最近在看shell。。。
在大学,谭浩强的C语言还算好,不太坑爹。有的地方讲得还是很深的。但是,清华吕XX的C++教科书实在是太坑爹了,所有知识点讲得浅不说。在对于>> <<运算符的使用时,更起到了举足轻重的误导作用。以下正文
cin,cout 是istream ostream类的对象,>>,<<为该类对它的重载。原型没有见过,不过目测应该是这样的:
istream& operator >>(const istream & stream, const int i)
istream& operator >>(const istream & stream, const char c)
istream& operator >>(const istream & stream, const char *s)
….
其中const istream & stream 形参的输入为cin 而后面的i,c,s输入为cin>>s等后面那个参数,可以看出来istream 对于不同基本类型的参数,分别进行了不同的重载。这样一个cin就可以进行不同的输入了(对于cout来说也是一样的)。
清华吕XX的C++的误导在于:它将>>和<<的重载单独拉到IO流库里面讲解,并把对它们的重载只用诸如:ostream& operator << (ostream&o MyClass &class)之类的例子来讲解,让童鞋们误以为>> << 为cin,cout专有的。>> <<只能重载为输入输出功能的函数。这里举个>>,<<重载为其他功能的例子:
ClassMyClass
{
….
MyClass & operator>>(MyClass&a){return (a =(*this));}
….
}
这个重载将>>重载为一个向右赋值的操作符,并支持链式表达
Eg:MyClass a,b,c
a>>b>>c;
theresult is a==b==c