lgxqf  

构造函数异常处理

http://www.mangbar.com/document/8a80809d19fb0c61011a056dbbb71b73


 

临时变量的产生与常引用

临时变量的产生:当对象对传值方式传递给函数参数或被传递给一个const 引用时才会发类隐式转换从而产生临时变量。
函数在传值方式返回时也会产生临时变量。这个对象是返回值的副本。

 

 

void bar( const string& s){};
void foo( string a){}

void err( string& s){};

//下述两种情况会发生隐式转换
bar(“abc”);//以abc为参数构造一个临时的string
foo(“abc”);//以abc为参数构造一个临时的string

err(“abc”);编译不过 因为对临时对象的修改是无意义的。

Char 的取值范围

-128~127 -128占用的是-0的位置

 

补码: 最高位为符号为 正数为0,负数为1
正数的补码和原码相同
负数的补码是最高位不变,后面位都取反,最后再加1

 


堆栈的增长方向
X86系统中,栈由上往下, 由高地址(0XFFFF)往低地下(0X00000)方向增长

0XFFFF

栈底

|

|

|

栈顶

0X0000

 


 

构造与析构异常

C++在执行构造函数过程中产生异常时,是不会调用对象的析构函数的,而仅仅清理和释放产生异常前的那些C++管理的变量空间等,之后就把异常抛给程序员处理。
如果析构函数抛出异常,将直接导致当前执行线程异常终止!如果是主线程中发生析构异常,程序立即退出!永远不要在析构函数中抛出异常
The best way to handle the constructor failure is to throw an exception in constructor.

 


 

高地址 低地址 高字节 低字节

高地址:0XFFFF 低地址:0X0000
 
Char s[4] = “ABC”;
Int val = 0x12345678
 
低字节:A78 高低字节:C 12

指向变量的指针 总是指向变量的低地址    char *p =(char *) &val;   printf("%d",*p); //78  Little Endian

 

大尾(Big endian)与小尾(little endian) 区别

X86系统采用的是little endian,网络上传输采用的是大尾
little endian 采用高高低低原则上即低字节在低地址 即最开始读的字节是字节流中的低字节.big endian与之相反
以上两个变量在little endian时的布局
0X0001    A     78
0X0002  B      56
0X0003  C     34
0X0004  ‘\0’   12

Big endian的布局
0X0001    ‘\0’   12
0X0002  C      34
0X0003  B     56
0X0004  A     78

bool IsLittleEdian()
{
  union un
  
{
    
char  c;
    unsigned 
short int i;
  }

  
  un data;
  data.i
=1;
  
  
return 1==data.c;
  
//char 在union中一直处于低字节,在小尾中它处于低地址 ,在大尾中处于高地址。
}

 

函数指针"非静态成员函数的函数指针"非静态成员变量的指针:

注意红色的小括号 是必须的 否则会编译出错.

class TM
{
public:
    TM(
int val = 0):data(val){}

    
bool SetData(int val)
{data = val; cout<<"data value is set as"<<data<<endl; return true;}
    
    
int data;

}
;

typedef 
bool (TM::*ClassFunPointer)(int);
typedef 
int TM::*DataMemberPointer;

ClassFunPointer clsFunPointer 
= &TM::SetData; 
DataMemberPointer dmPointer 
= &TM::data;

TM tm;
(tm.*clsFunPointer)(10);
tm.
*dmPointer =1;

 


 

动态对象数组与指针数组:

 

class Test
{
public:
            Test()
{cout<<"Test"<<endl;}
            Test(
int a){cout<<"Test "<<a<<endl;}
            
~Test(){cout<<"des constructor"<<endl;}
}
;
 
不要用基类指针指向一个子类的数组,因为在删除该数组时除非做显示转换 否则会出错。
Base 
*pB =new Derived[2];
 
//Wrong way of deletion
delete[]pB//Cause core dump
 
//Correct way
for(int i=0;i<2;i++)
{
            Derived 
*pD = &(static_cast<Derived *>(pB))[i]);
            delete pD;
}

//Consider how about Derived *pD = static_cast<Derived *>(pB);delete [] pD;

 


构造不定长多维数组
 

指针数组:即数组里的每个元素是指针 Test *point[2];point是数组名,该数组含有两个Test指针
数组指针:一个指向一维或者多维数组的指针 Test *pAry = new Test[2];pAry是一个指针,它指向一个对象数组。
          int(*ptr)[3];//指针所指向的的类型是int()[3] //二维指针的声明
          int (*b2)[10]=new int[10][10]; 注意,这里的b2指向了一个二维int型数组的首地址
          int (*a1)[2][3]; a1= new int[4][2][3];//a1是个指针,它指向一个三维数组
 
          int(*b3) [30] [20]; //三级指针――>指向三维数组的指针;
          int (*b2) [20];     //二级指针;
          b3=new int [1] [20] [30];
          b2=new int [30] [20];
          两个数组都是由600个整数组成,前者是只有一个元素的三维数组,每个元素为3020列的二维数组,而另一个是有30个元素的二维数组
          每个元素为20个元素的一维数组。
          删除这两个动态数组可用下式:
             delete [] b3; //删除(释放)三维数组;
             delete [] b2; //删除(释放)二维数组;

 


 

构造动态指针数组/不定长的多维对象数组

            int lenA=2;//第一维
            int lenB=3;//第二维
            Test **pointAry= new Test*[lenA];//含有lenA个指针的动态指针数组
 
            int i=0;
            for(i=0;i<lenA;i++)
            pointAry[i] = new Test[lenB];
           
            pointAry[0][0] =1;//给对象数组中的第一个对象赋值
 
            for(i=0;i<lenA;i++)
            delete []pointAry[i];

 


 

变量初始化:

Global object(全局变量)的内存保证会在程序激活的时候被清为0
Local object(局部变量)配置于程序的堆栈中, heap object(堆变量)配置于自由空间中。二者都不一定会被清0。它们的内容将是内存上次被使用后的遗迹。

 


慎用 delete this

class MB
{
   public:
           void Foo
(){ delete this;}
}
int main
()
{
    MB *p 
= new MB;
    p-
>Foo();
    delete p
; //Cause crash! Because memory pointed by this is already freed.
}

 


unsigned int 在类型转化时候优先级比int高

unsigned int a = 6;

int b = -20;

(a+b>6)?puts(">6"):puts("<6");

a+b 时转化为unsigned int,所以数值非常大,输出>6.

printf("%d",a+b);//输出-14,因为“%d”,把unsigned int 的(a+b)又转化为 int。

printf("%u",a+b); 才正确

 


 ++优先级比*高

   char a[] = "Hello!";
   char *p 
=a;

   char c = *p++;

  

   cout<<c; //结果是 H

   cout<<p; //结果是 ello



虚函数

 

代码
class A
{
public:
virtual void f1(){cout<<"f1"<<endl;}
virtual void f2(){cout<<"f2"<<endl;}
virtual void f3(){cout<<"f3"<<endl;}
};

class B:public A
{
public:
virtual void f2(){cout<<"B:f2"<<endl;}
};

class C: public B
{
public:
virtual void f3(){cout<<"C:f3"<<endl;}
};


int main()
{
C c;

A
*p = &c;

p
->f1(); //f1
p->f2(); //B:f2
p->f3(); //C:f3
}


 

 


    DeriveA  derA;
    derA.fun();//OK

如果重新定义了基类中的的一个重载成员工函数,则在派生类中其他的重载函数将会被隐藏

 

代码
class MBase
{
public:
virtual void fun(){};
virtual void fun(int a){};
};

class DeriveA : public MBase
{
public:
//重写基中的一个重载函数
virtual void fun(){};
};

class DeriveB : public MBase
{
public:
//新加一个函数
virtual void fun(char *c){};
};


int main()
{
DeriveA derA;
derA.fun();
//OK
//derA.fun(1);//Error! 基类中的fun(int)在子类中被隐藏,因为子类重新定义了基类中的fun(), 它在基类中是重载函数

DeriveB derB;
//derB.fun();//Error 子类中新定义的fun(char c) 隐藏了fun()和fun(int a)
//derB.fun(1);//Error 原因同上
derB.fun("abc");//OK

MBase
*base = &derB;
base->fun();//OK
base->fun(1);//OK

return 0;
}

 

 


构造函数不能为虚 但类中有至少一个虚函数,析构函数必须是虚的。

虚机制在构造函数中不工作,构造函数中调用的函数都是静态连编的。即使构造函数中有虚函数,也把它视为非虚函数。

虚机制在析构函数中也不工作,析构函数中调用的函数都是静态连编的。即使析构函数中有虚函数,也把它视为非虚函数。

 


posted on 2009-06-25 10:24  Justin_Ma  阅读(376)  评论(0)    收藏  举报