C++的一些深入理解

以下内容结合本人的一些总结加上网上的一些资源整合,是本人工作中感悟出来的一些经验,仅供参考,如有不对,敬请指正


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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值