以cocos2d-x之名:c++知识回顾二

来源:互联网 发布:工业企业数据库 161 编辑:程序博客网 时间:2024/04/30 13:32

   今天跑步上班的 , 四公里 还背着包 ...平时连自行车都懒得骑的说 ... 累死个人了...趁着还没上班 ,继续 .


字符字面量:
‘*’
  在C语言中没有真正的字符字面量,用的实际都是int .
#include<stdio.h>int main(){    printf("%d\n",sizeof('x'));//c    return 0 ;}

以上输出结果是  4


而 C++ 输出 1


void * 类型 在c语言中可以和任何地址类型相通 ,在c++中严格限制 ,不能赋值给其他地址类型.



C++是强类型语言 .



#inlcude<iostream>using namespace std;enum Color{    RED,GREEN,BLUE};int main(){    Color c;//    c = 1 ; //这个是不允许的 //从int 到Color的转换无效     void * p = &c;    Color* q;    q = p ; //从 void* 到 Color* 的转换无效     return 0 ; }
以上程序在c中是没有错误的 .


在C 语言中调用一个函数 ,即使没有声明,也是可以调用的,默认是 int类型 ,而C++ 是绝对不允许的
Void*  在c++中理解为 丢失了类型的地址 . 而不是和c一样可以匹配所有的类型 .
通过强制类型转换,可以完成赋值:
C= (Color)1 ;
还可以写成 C= Color(1) ,C = (Color)(1) ;
类型转换:
  强制类型转换在c的基础上增加了一种形式: 类型(数据)
  在c++中不提倡用强制类型转换.如果确实需要类型转换 ,c++ 提供了另外四种方式:
static_cast<类型> (数据) 用于数值类型之间以及 void* 和其他*类型之间(不能用于其他*类型之间,一方只能是void*)
reinterpret_cast<类型>(数据) 用于数值类型与地址类型之间,或者地址类型相互之间的转换.
const_cast<T* >(T常量地址) 去掉地址所指向的目标的const限制

dynamic_cast  在面向对象的部分讲解
在c++中用以上取代强制类型转换 :
  1 便于搜索
  2 因为输入繁琐,会让人不想用…


volatile 不稳定的,表示某个变量的值可能因为某种原因被改变 .

通过繁琐,来慢慢抛弃类型转换,去改变设计,发现不需要类型转换了.也就对了 .

函数:
C语言的函数有潜规则:
  1 默认返回 int 类型 ,在c++ 作废
  2 函数的参数表可以是空的,表示参数个数随意 .c++中只表示无参 .(c语言表示无参要用 void )


因此函数在调用前必须要声明或者定义 .
 重载:  c++允许多个函数使用相同的名字 ,但是要求要有不同的参数表(即类型或者个数或者顺序不同 ,原则就是让编译器能分清该调用哪一个) .编译器无法区分调用哪一个的时候,就会导致编译错误 .自动类型提升依然适用


重载:

#include<iostream>using namespace std;void show(int n){    cout<<"integer"<<n<<endl;}void show(double d){    cout<<"decimal"<<d<<endl;    }void show(int n ,int m){    cout<<"a couple of integer"<<n<<','<<m<<endl;}struct Person{    char name[20];    char gender;    };void show(Person p){    cout<<"one "<<(p.gender=='M'?"male":p.gender=='F'?"woman":"alien")<<"name is "<<p.name<<endl;}int main(){    show(123);    Person fj={"luoyufeng",'N'};    show(fj);    show(45.6);    show(78,90);    }

重载与返回类型无关

形参的默认值: 如果函数的某个形参在调用时绝大多数情况下都传递的是某个特定实参,那么就可以把这个实参值指定为这个形参的默认值,调用时可以不再传递 .
有默认值的形参必须靠右 
XX ShowWindow(int mode=NORMAL)

#include<iostream>using namespace std;void show(const char* name,char gender='M');int main(){   show("liming");   show("dongda");   show("wangtong",'F');   show("qigaobao");   return 0 ;}void show(const char* name,char gender) //为了防止输入错误,默认值在声明里写,在定义的时候不能写{    cout<<name<<"is a "<<(gender=='M'?"ladykiller":gender=='F'?"bella":"alien")<<endl ;    }

声明和定义分开的时候,形参默认值放在声明中.

 
函数的哑元 : 旧版本可能有更多的参数,新版本不需要如此多的参数,但是又要和旧版本兼容,所以多余的参数作为哑元
  不需要制定名字,一般是为了跟以前的版本兼容.偶尔也用于其他人为的用途.
show(int) show(int,bool)
sort(int a[],int n ,int)

c语言里面的宏函数,看着像函数,其实不是函数 .在c++里面基本已经不用了 .因为宏没有声明类型,不符合c++的强类型的要求 ,同时,因为对++处理的副作用  .
C++中取而代之的是内联函数 ,用 inline表示 .
 内联函数会在调用的地方展开函数代码,而不是产生调用,和宏一样高效,但却有明确的参数类型而且没有副作用.
 是否真正执行inline的要求,完全由编译器自己决定.

内存管理: c语言 malloc/free/calloc/realloc
以上有个缺点是c++不能容忍的,返回值是 void* 
c++
new 类型 
new 类型[元素个数]
释放用delete 地址
delete [] 地址
还有一个比较怪的用法
new(指定地址) 类型: 在指定的地方分配内存(少用)

#include<iostream>#include<cstring>using namespace std;int main(){  int * pi= new int;  int n = 200;  char* pc = new char[n];  double* pd = new long(123);  short *ps= new short(); //初始值直接给()的称为 零初始化  *pi=12*101 ;  strcpy(pc ,”Tarena welcome you ”);  pd[10] = 1234.5 ;  cout<<*pi<<pc<<pd[10] <<*pl<<* ps;  delete pi ;  delete[] pc;  delete[] pd;  delete pl;  delete ps;}

段错误:非法的内存访问 ,细节在uc的时候讨论

零初始化:
char *p = new char();
*p ==?’0’: ’\0’
是’\0’ ,它的数值是 0
字符0 的数值是 48

new 失败会抛出异常 .导致程序终止 ,可以用nothrow来在申请内存失败时像c的内存管理函数一样返回NULL ,头文件<new>
 古怪的关键字,用来表示运算符:
 and ,or ,not ,and_eq , or_eq ,not_eq , bitand, bitor,xor ,compl

古怪的指针: 成员指针
struct Date{
              int year;
              int month;
              int day;
};

int Date::*  p = &Date::year  成员指针
p =&Date::month ;
使用方式:
Date a = {2013 ,1,16 } ,b ={2008,8,8} ;

示例程序 :成员指针

#include<iostream>using namespace std;struct Date{              int year;              int month;              int day;};//sort functinvoid sort (Date a[] ,int n, int Date::*p){    for(int i=0;i<n;i++)        for(int j=i+1 ;j<n;j++)            if(a[i].*p > a[j].*p)                swap(a[i],a[j]);}int main(){int Date::*p= &Date::year  p = &Date::month ;  Date a = {2013 ,1,16 } ,b ={2008,8,8} ;  count<< a.*p<<b.*p <<endl ;  p=&Date::day ;  count<< a.*p<<b.*p <<endl ;}

引用:
如果用c的知识来写一个交换变量的函数:
#include<iostream>using namespace std;void swap(int* p ,int* q){int t =*p ;   *p = *q ;   *q = t ;} //因为是值传递 ,也就是拷贝,所以一定是地址


如果使用引用,程序可以改进:

#include<iostream>using namespace std;void swap(int& p ,int& q) //告诉编译器,这里传进来的是地址{    int t =p ;  //无需加 *        p = q ;       q = t ;} int main (){    int a = 10 ,b =20 ;    swap(a , b) ; //这里可以直接使用    cout<<a<<','<<b<<endl ; return 0 ;}

引用:
本质上是指针(地址) ,编译器自动取地址,加* .就是编译器把细节隐藏了.
c++ 里面是引用传递 ,不是复制过去 .

定义: 类型&名字= 初始值 ;
引用必须初始化 , 使用谁初始化它,它就跟谁同一体 ,这种关系不会改变 .
特别说明: 形参是在调用时,由实参初始化 .返回值实在返回时由return后面的数据初始化.


int sum (int a ,int b){   int s = a+b;   return s;}int x= sum(3,5) ;

这个地方其实是用 return 的s来初始化返回值.

注意:每次的调用算作一次初始化 .

引用使用变量本身(同一体)而不是复制数据,改变引用变量的值,也就改变了她的同一体的数据值 .特别说明,引用并不是新数据类型  ,而是表示传递方式.
 当我们在c中使用*的时候,确实传递进去的不是简单的int类型 .而引用是原来的类型(int) 
 使用引用可以省去复制过程,节省时间和内存

mini 函数:
计数函数的实现

int * counter(){  static int cnt = 0 ;//静态局部变量  ++cnt ;  return &cnt ;}

调用完毕的清零:

*counter = 0 ;

换成引用的:

int& counter(){  static int cnt = 0 ;//静态局部变量  ++cnt ;  return cnt ;}counter() = 0 ;

因为同一体的特性,保证都是同一个cnt ,避免了不安全的问题













0 0