C++的一些基础细节(备考用)

class  node
{
public :
node(){cout
<< " constructor node() " << endl;}
~ node(){cout << " destructor ~node() " << endl;}
};
class  nn
{
public :
node x;
nn(){cout
<< " con nn() " << endl;}
~ nn(){cout << " des ~nn() " << endl;}
};
int  main()
{
nn a;

return   0 ;
}

 

  几年前的一份C++笔记。

  看完了Bruce Eckel的Thing in C++(Volume 1),实践比较少,感觉还是半懂不懂,马上就要【面向对象程序设计】的考试了。考的是C++的东西,做了几份C++的卷子,感觉好多细节的东西还是很不确 定,不敢下手。于是今天把老师的课件翻了出来,整理了一下,做了个小结。虽然感觉很乱,但是对于我自己来说,还是能看懂,很多东西都很显而易见的也写了, 无论怎样,只是为了考试^_^


extern int xx 这是一个声明,而不是定义

在class temp中只定义一个static int b;

1  sizeof (temp)  =   1

这是为什么?
static 变量是这个类共享的,变量是放在全局变量区,不是堆栈里,因此sizeof出来不算在这个static int的大小;是这样的吗??


枚举类型的变量只能进行赋值运算


指针int *p,后不能直接进行*p = 12这样的赋值,因为指针p没有申请内存


如何解释以下程序?

1  int  main()
2  {
3  int   * a;
4 
5  =  ( int   * ) " string " ;
6  cout <<* a << endl;
7  cout << a << endl;
8  return   0 ;
9  }

a指向一个string常量的,强制转换为int *,因此a还是"string"常量的首地址,*a应该是取前面几位的值


析构函数的调用不一定要大括号

class  node
{
public :
   node(){cout << " node() " << endl;}
   ~ node(){cout << " ~node() " << endl;}
};
int  main()
{
   if ( 1 )
  
   node n;
   cout << " out of if " << endl;

   return   0 ;
}

输出为
node()
~node()
out of if
另外,一个大括号就是一个scope,不管有没有if,while等语句


if(!cin)
相当于if(cin.fail())
!的运算符在这里被重载了


函数中的static变量在结束main()的时候才释放,但是在全局变量之前


全局变量区:全局变量,静态全局变量,静态本地变量
stack:本地变量
heap:申请的变量,例如,new,malloc
要注意的是new和malloc不能混用


class 中的public表示所有的object都能访问
private只能让类声明的函数和friend函数访问
protected可以子类访问,也可以被friend函数访问


无论是数组还是指针,传到函数中都变为指针


只有在没有构造函数的情况下,编译器才自动分配一个构造函数,否则,只要
编译器看到一个构造函数,就不会生成一个构造函数。
另外,编译器自动生成的构造函数是没有参数的。


根据函数的参数的个数或者类型的不同可以重载函数。
如果只是返回值不同,则不能重载。


缺省参数的函数。缺省值只能从后往前写。

也就是说int f(int i , int j = 0);是可以的。
但是int f(int i = 0 ; int j);是不对的。


一个class中如果有const 常量,声明的时候不能初始化,否则编译器报错

但是如果是static const int a = 0就可以
class中的const int a可以在构造函数中初始化,注意只能在初始化列表中,不能在函数体中赋值
其他的地方定义const 则需要初始化
如果是extern const int a ;就可以不做初始化


内联函数应该放在.h的文件中,因为它是一个声明
另外在class中定义的函数是内联的


1  const   int  a  =   10 ;
2  int  y  =  a;

是可以的


1  const   int  size  =   10 ;
2  int  a[size];

是正确的。
但是

1  int  x  =   10 ;
2  const   int  size  =  x;
3  double  classAverage[size];

会报错(为什么?)


1  const   int  size[ 3 =  { 2 , 3 , 4 };
2  int  a[size[ 0 ]];

是错的。
也不能这样定义

1  struct  S {  int  i, j; };
2  const  S s[]  =  { {  1 2  }, {  3 4  } };
3  double  d[s[ 1 ].j];

1  char   *   const  p  =   " abc " ;

表示p指向的地址是常量,指向的地址不能改变,但是指向的内容可以变

1  char   const   * =   " abc " ;

表示p指向的内容是常量,不能改变,但是指向的地址可以改变


 1  int   * ip;
 2  const   int   * cip ;  // 指针可以不初始化
 3  const   int  t  =   3 ;
 4  int  i;
 5  ip  =   & i ;
 6  ip  =   & t ;  // 错误,非常量指针不能指向常量
 7  cip  =   & i;
 8  cip  =   & t;
 9  * ip  =   54 ;
10  * cip  =   54 ; // 错误


1  char   *  s  =   " hello , world " ;

是可以的,因为编译器自动转化为

1  const   char   *  s  =   " hello,world " ;

因此不能再改变s的值了。 但是s指向的地址是可以改变的


void  f( const   int  x){}
void  g( int  x){}
int  a  =   0 ;
const   int  b  =   0 ;
f(a);
g(b);

都是可以的


如果返回值是const,可以赋给non-const,如果不是const 也可以赋给const

如果一个对象定义的时候是const,不能修改这个对象的值

int  node::f() const

函数中不能修改成员变量
也不能调用非常量函数

int  node::f(){}
int  node::g() const {f();}

是错的。


不能这样定义

class  node
{
private :
    
const   int  size;
    
int  a[size];
};

可以把const int 改为static const int
或者用enum来做


引用不能改变

int  y , z;
int   & =  y;
& =  z; // 错误,引用不能改变

int  f( int   & ){}

不能调用f(t * 3);


不能这样定义

int &*  p;

但是可以这样

int *&  p;

引用变量的构造函数中也只能初始化,而不能赋值


如果函数的返回值是const的,就不能做左值


在node a = b;或者node a(b);拷贝构造调用。
当函数返回一个对象的时候,拷贝构造被调用

node f()
{
    node x;
    
return  x;
}

在函数的参数中有对象的时候,调用拷贝构造

int  f(node x)
{
    
return   1 ;
}

但是如果参数的引用,拷贝构造不被调用

int  f( const  node & )
{
    
return   1 ;
}


静态函数只能对静态变量进行操作



函数中的静态变量只能被初始化一次



static 成员变量在同类的对象中都可见



不能用this来取值



namesapce
可以用using nm::f();

void  main() {
using  MyLib::foo;
using  MyLib::Cat;
foo();
Cat c;
c.Meow();
}




namespace  my1
{
int  f(){cout << " my1::f() " << endl; return   0 ;}
int  g(){cout << " my1::g() " << endl; return   0 ;}
}
namespace  my2
{
int  f(){cout << " my2::f() " << endl; return   0 ;}
int  h(){cout << " my2::h() " << endl; return   0 ;}
}
int  main()
{
using   namespace  my1;
using   namespace  my2;
f();
g();
h();

return   0 ;
}

编译器报错,因为编译器不知道应该调用哪一个f(),
如果不调用f(),编译器就不会报错了。
但是如果将f()变为my1::f()就可以了
注意namespace后面没有";"



【运算符重载】



可以重载的运算符:
+     -     *     /     %     ^     &     |     ~
=     <     >     +=    -=    *=    /=    %=
^=    &=    |=    <<    >>    >>=   <<=   ==
!=    <=    >=    !     &&    ||    ++    --
,     ->*   ->    ()    []   
operator new        operator delete
operator new[]      operator delete[]



不能被重载的运算符
.      .*      ::      ?:
sizeof    typeid
static_cast    dynamic_cast
const_cast     renterpret_cast
另外不能重载不存在的运算符,例如**



运算符重载后的优先级不变
所接受的参数的个数也不变



重载为成员函数,可以省略第一个参数,但是
z = x + y;//可以
z = x + 3;//可以
z = 3 + y;//不可以
因为只看第一个参数
但是如果重载为全局函数,以上三个表达式都正确



必须是member function:
= () [] -> ->*
还有一元的运算符必须是member function
所有的二元运算符可以是non-member fuction



函数原型:
+    -   *    /    %    ^    &    |    ~
const T operatorX(const T& l, const T& r);
!    &&   ||    <    <=    ==    >=    >
bool operatorX(const T& l, const T& r);
[]
T& T::operator[](int index);



++ -- 运算符的重载

const  Integer &   operator ++ ();  // ++a
const  Integer  operator ++ ( int );  // a++
const  Integer &   operator -- ();  // --a
const  Integer  operator -- ( int );  // a--

在后缀++重载的时候,应该先将原来的对象保存下来用来返回
在调用a++的时候,实际上调用的是a.operator++(0)
//前缀比后缀更加高效



关系运算符的重载

bool   operator == const  Integer &  rhs )  const ;
bool   operator != const  Integer &  rhs )  const ;
bool   operator < const  Integer &  rhs )  const ;
bool   operator > const  Integer &  rhs )  const ;
bool   operator <= const  Integer &  rhs )  const ;
bool   operator >= const  Integer &  rhs )  const ;


【继承】



输出:
constructor node()
con nn()
des ~nn()
destructor ~node()



在构造函数调用的时候,总是基类先被调用
而析构函数的调用与构造函数的调用是反过来的



如果在子类定义了一个函数与父类的名字相同的话,父类中所有同名的函数被屏蔽



继承后
构造函数,析构函数,operator=,private不能被继承
子类不能访问private的变量,但是可以访问protected的变量



在继承中
class base:derived默认为private继承



class derived:public base
base的public在derived是public,protected在derived是protected,private在derived中被 隐藏
class derived:protected base
base的public在derived是protected,protected在derived是protected,private在 derived中被隐藏
class derived:private base
base的public在derived是private,protected在derived是private,private在derived中被隐 藏



upcasting
base &b = pete;//pete是子类,base是父类
b->f();
调用的是父类的f();
但是如果父类的f()是virtual的话,调用的是子类的f()



void  func(Ellipse &  elly) {
elly.render();
}
Circle circ(60F);
func(circ);

调用的是Circle::render();
但是如果

void  func(Ellipse elly) {
elly.render();
}
Circle circ(60F);
func(circ);

调用的是Ellipse::render();



析构函数也可以virtual,作用与前面一样

base   * =   new  derived;
delete p;

如果析构函数是virtual的,调用的是derived的析构函数,同时也会调用base的
否则调用的只是base的



overriding
可以这样定义:
在base中:virtual base& f();
在derived中:virtual base& f();
但是不能这样定义
在base中:virtual base f();
在derived中:derived f();



当override一个函数的时候,最好重载所有的函数



在构造函数中调用的virtual function是本身的f()



template < class  T >
void  swap(T &  a , T &  b)
{
    T temp;
    temp 
=  a;
    a 
=  b;
    b 
=  temp ;
}

不能这样调用

int  a;
double  b;
swap(a,b);


template < class  T >
void  foo(){ /* ******** */ }
foo
< int >   // 此处的T为int




类的模版
template<class T>
class node.....
创建对象的时候,可以
node<int>...
如果函数不是内联的,在函数的定义的时候,前面要加上
template<class T>



template<class T , class U>
template<vector<class T> >注意后面是有空格的



也可以是变量
template<class T , int size>
可有带有缺省参数
template<class T , int size = 100>



模版可以用在继承上
template <class A>
class Derived : public List<A> {...};



模版应该放在.h的文件中



【异常】



try{}catch(){}catch{}



catch所有的异常
catch(...);



关于new的异常处理

void  func() {
try  {
    
while ( 1 )
    {
        
char   * =   new   char [ 10000 ];
    }
    } 
catch  (bad_alloc &  e)
      {
      }
}




还有一些stream的东西还没看。

另外,template和exception的貌似不怎么考,因此比较少T_T

转载于:https://www.cnblogs.com/vivyli/archive/2010/02/05/1664061.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值