c++基础知识笔记一

12年前


 C++
 
 C++基础语言与C语言差不多是一样,只是多了些内容,变了些内容
 C++类型检查更严格,更加丰富
 面向对象
 
 C++变量里面不仅是数据,还有函数;
 封装,基本目的:我的数据是安全的
 继承和多态
 
 c++还增加了模版,通用类型编程;
 异常处理
 
 g++
 c++
 
 gcc
 cc
 
 vi xxx.cpp  cpp===>c plus plus或者.cc,.C,.cxx的扩展名
 c++头文件以.h或者.hpp
 
 编译g++
 只编译g++ -c xxx.cpp==>xxx.o
 
 g++ xxx.o===>a.out;g++ xxx.o -onewname
 
 g++ xxx.cpp===>a.out;g++ xxx.cpp -onewname;
 //注释
 
 
 在c++中输入输出更多的是用cin/cout,其头文件是iostream
 
 namespace===>
 标准库都放在std的一个名字空间里面;
 //using namespace std;//即可使用这个名字空间下的东西了。
 
 
 vi  hello.cpp
 #include <iostream>//input/output stream
 #include <string>
 //using namespace std;//意味着标准库中的所有东西都可用,在本例中可以采用以下方式替代。
 using std::cout;//可以采用A::B来表示A范围内的B,“::”称为域操作符
 using std::cin;
 using std::string;
 using std::endl;
 
 int main()
 {
  //在c语言里面使用scanf/printf,用%d等来使用;根据不同类型用不同的类型标识符
  cout <<"请输入您的姓名和年龄:\n";//不管什么类型的数据都可以
  //std::cout<<"请输入您的姓名和年龄:\n";//也可以不引进namespace,直接采用这种方式直接来使用
  string name;//不需要指明多少个元素;使用的是动态内存,
  int age;
  cin >>name >>age;
  cout <<name << "您好,您出生于"<<2012-age <<"年”
   <<endl;//endline==>'\n';c++里面允许用endl来换行
  
  //return 0;//在c++中末尾的return 0是可以不写的,但不代表没有。
 }
 
 g++ hello.cpp
 a.out
 
 
 
 vi namespace.cpp
 #include <iostream>
 using namespace std;
 #include <string>
 namespace lhj{//自己定义命名空间
  string name="老虎机";
 }
 namespace sxl{
  char name[20]="hahahhaha";
 }
 using namespace lhj;
 using namespace sxl;
 char name[20]="wl";
 int main()
 {
  //count <<"i love" << name <<endl;//歧义:老虎机?hahahhahahah
  count <<"i am" << lhj::name <<endl;
  string name="chch";
  cout << name << "very beautiful" << endl;//内部的name:chch
  cout << ::name <<"very beautiful,too" <<endl;//全局的name:wl
  //在这里::表示全局的name或者外部的name
  return 0;
  //设计的时候,尽量避免重名
 }
 
 string字符串类型,实际上就是封装的类型;封装的是指针和一系列的函数
 
 对比string与char str[100](这两个都可以保存数组)
 string s1;//最大保存1个G==>c++风格的字符串===>=号就可以赋值==》连接用+=就可以=》比较==,!=,>,<,<=,>=
 char===>大小s1.size()/s.length()==>s1.find(...)查找==》s1[i]访问某个元素===》s1是一个变量 s2[100];//保存99个字符+1个'\0';==>c风格字符串===strcpy(s2,...)=》连接strcat(s2,...)==》strcmp(s2,...)比较==>strlen(s2)==>查找,strchr或者strstr(s2)==》访问某个元素s1[i]===》s2是一组变量
 
 在c风格和c++风格转换,c风格会自动转换成c++风格;c++风格转换成c风格,使用s1.c_str()
 
 
 
 enum
 在c里面当作整数,而在c++里面
 
 #include <iostream>
 using namespace std;
 #include <string>
 enum Course{UNIX,C,CPP,UC,VC};
 struct Student{
  string name;
  Course co;
 };//定义一个结构
 enum Color{BLACK,RED,GREEN,YELLOW,BLUE,WHITE};
 int main()
 {
  Course c;
  Student s;
  int n;
  c=CPP;
  n=CPP;//这样是可以的
  //c=n;//这样就会报错,enum在C++当作是一个独立的类型;enum提升成int类型是可以的
  Color clr=BLUE;
  //clr=VC;//Course--->Color必须强制转换
 
 }
 在C++中调用函数时不做类型提升,函数形参是...的函数按照C语言提升
 
 bool  true-1/false-0
 
 #include <iostream>
 using namespace std;
 int main()
 {
  bool gender=true;
  bool sex=false;
  cout <<(gender?"帅哥":"美女")<<endl;
  cout <<(sex?"boy":"girl")<<endl; 
  cout << gender << ',' << sex << endl;//输出1,0
  cout << boolalpha <<gender << ',' <<sex << endl;//输出true,false
 }
 
 引用reference==》给个变量,另起个名字(别名) T&
 vi reference.cpp
 #include <iostream>
 using namespace std;
 int main(){
 
  double d=123.45;
  double & e=d;//引用必须初始化,只能用变量来初始化;e是d的别名,两者是同一个变量
  //double * const E=&d;//后面的e都相当于*E
  //double & f=123.45;//是一个错误
  const double &c=234.56;//这是正确的常量引用
  const double &s=d+5;
  cout << "&d=" << &d << ",&e=" << &e << endl;
  //int & n=d;//类型不一致
  cout << "d=" << d << ",e=" << e << "c=" <<c << "s=" << s << endl;
  double & e2 = e;
  cout << "&e2=" << &e2 << ",e2=" << e2 <<endl;
  e2=78.9
  cout << "e2=" << e2 << "d=" << d << endl;
 }
 
 引用的本质就是指针
 
 
 vi const.c
 #include <stdio.h>
 
 int main()
 {
  const int n=100;//n是常量;后面使用n的值的地方会直接用100代替
  volatile const int m=200;//不管何时都从内存中去重取,不管是c还是c++
  int *p=(int*)&n;//通过n找到内存地址
  *P=123;//将*p的内容更改为123
  p=(int*)&m
  *P=456;
  printf("%d,%d\n",n,m);
  return 0;
 }//耍流氓喽
 使用cc const.c
 执行后n为123

 g++  const.c时,显示为n=100;//经常c++编译器之后,编译器会优化;常会再从内存中读取。量
 
 
 g++ -S const.c//会产生汇编语言;
 
 c++里面提倡不要做强制类型转换;
 
 C++提供了4个强制类型转换的算子
 static_cast | const_cast | reinterpret_cast | dynamic_cast
 //static_cast数值类型之间,有一方是void*的指针类型之间
 //const_cast把常量转换成变量,用于临时去掉const限制
 //reinterpret_cast用于任意两种指针类型之间,以及指针类型与数值类型之间转换;==》最危险的一种转换
 //dynamic_cast用于父子类之间
 //属于什么原因来转换;两种不相关的类型转换;_cast
 
 #include <iostream>
 using namespace std;
 #include <cstdlib>  //c语言头文件在c++中有个对应的头文件,即类似<stdlib.h>---><cstdlib>
 int main()
 {
   //int n=45.67;//x,可能换丢失精度
   int n=static_cast<int>(45.67);
   int *p=static_cast<int>(calloc(sizeof(int),10));//calloc(unsigned n,unsigned size)在内存的动态存储区中分配n个长度为size的连续空间,函数
   //返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。 //跟malloc的区别;calloc在动态分配完内存后,自动初始化该内存空间为0,而malloc不初始化,里面数据是随机的垃圾数据
    const int k=n;
    cout << "k=" << k << endl;
    const cast<int&>(k)=789;
    cout << "k=" << k << endl; 
    float f=123.45;
    p=reinterpret_cast<int*>(&f);
    cout << *p << endl;
    n=int(12.34);
    cout << "n=" << n << endl;
    n=int();//表示数值0
    cout << "n=" << n << endl;
    int m(100);
    cout << "m=" << m << endl;
    //int x();//函数声明
   
 }
 
 ~!|& 有些系统输入不了,都可以用关键字来代替如以下
 
 ~代compl   ^代xor   !代not  |代bitor  ||代or   &代bitand  &&代and
    &=代and_eq   |=代or_eq  ^=代xor_eq !=代not_eq
 
 -----------------------------------------------------------
 
 new  delete C++中提供动态内存
 new 类型;new就是申请一块内存
 vi new.cpp
 
 #include <iostream>
 using namespace std;
 #include <cstdlib>
 #include <string>
 #include <new>
 //new 类型===>(类型*)malloc(sizeof(类型))
 int main()
 {
  int *p=static_cast<int*>(malloc(sizeof(int)));
  int *q=new int;//与上面是等效的;//不保证是0
  int *r=new int(888);//申请一个空间,并设置其初始值为888
  int n=10;
  cout << "请输入一个整数:";
  cin >> n;
  int *a=new(nothrow) int[n];//可以通过new申请一个数组的空间,并返回数组的开始地址(第一个元素的开始地址);
  //会处理类型的问题
  //不保证清0;
  cout << *q  << ',' << *r <<endl;
  for (int i=0;i<n;i++){//int i,在这个for循环内可用,出了就不能用了。
   cout << a[i] << ' ';
   if (a[i]){
    cout << flush;
    char c;
    cin >> c;
   }
  }
  cout << endl;
  delete r;r=NULL;
  delete q;q=NULL;
  delete []a;a=NULL;//告诉系统删除的是一片空间,中间加[]
  //用new申请的,用delete释放
  
  free(p);//malloc申请的内存,不要用delete p
 }
 
 
 成员指针
 
 
 vi memberptr.cpp
 #include <iostream>
 using namespace std;
 //结构变量.*成员指针,结构指针->*成员指针
 struct date{
  int year;
  int month;
  int day;
  void print(){cout << year << '-' << month << '-' << day << endl;}
 };
 void showmemeber(date a[],int n,int date::*p)
 {
  for(int i=0;i<n;i++){
   cout << a[i].*p <<' ';
   //cout << *(a+i).*p << ' ';
   //cout << (a+i)->*p << ' ';
  }
  cout << endl;
 }
 int main()
 {
  date a[5]={{2010,8,17},{2010,10,1},{},{},{}};
  date d{1997,7,7};
  cout << "&d=" << &d << endl;
  cout << "&d.year=" <<&d.year << ",&d.month=" << &d.month << "&d.day=" << &d.day << endl;
  //&date::year;//取相对地址
  cout << &date::year << &date::month <<&date::day << endl;
  cout << &main <<&f <<endl;
  
  union{
   int n;
   int date::*mp;//成员指针
   
  };//这两个变量占用同一个内存空间;
  mp=&date::day;
  cout << "n=" << n << endl;
  cout << d.*mp <<endl; //.*当作一个运算符
  mp=&date::year;
  cout<<d.*mp<<endl;
  showmember(a,5,&date::month);
  showmember(a,5,&date::year);
  d.print();
 }
 
 
 
 
 #include <iostream>
 using namespace std;
 
 void f1(){cout << "hello" << endl;}
 void f2(void){return f1();}
 void f3(double){cout <<"world" <<endl;}//有类型无名字:哑元;一般是兼容性的考虑
 int main()
 {
  //f1(123);函数f1是无参的
  f1();
  f2();
  f3(12.3);
 }
 
 
 c++标准库包含了c语言的标准库,又进行了扩展以及标准模版库STL
 
 引用必须有变量才行;常量引用必须加const
 常量必须有const
 函数地址只能用来调函数
 成员地址能用用来访问成员
 函数地址和成员地址在输出的时候,c++中都强制处理成true或1,不管是什么东西。怎么访问呢?可以通过联合union来访问;而在c语言中,访问的可能就是地址
 
 
 引用一般最多的是作为形参或者返回值、返回类型
 
 #include <iostream>
 using namespace std;
 
 int main()
 {
  int i;
  for (i=0;i<5;i++)
  {
   cout << i << endl;
  }
  cout << i << endl;
 }
 //在c语言中,for (int i=0;i<5;i++)  //这个i只在for循环范围之内,而在vc中再可以在内外都可以
 
 引用作为函数的形参,可以减少数据传输的数量;比如结构变量,如果只是一个基本类型变量就无所谓了。
 
 #include <iostream>
 using namespace std;
 void JiaoHuan(int *a,int *b){int t=*a;*a=*b;*b=t;}
 void JiaoHuan(int& a,int& b){int t=a;a=b;b=t;}
 void print(cont int & n)//用16进制输出
 {
  cout << hex << showbase << n << endl;//hex16进制,showbase显示几进制
 }//8进制0开头,16进制0x,10进制什么都不带
 
 struct Window{
  string text;
  int x,y;
  int width,height;
 };//GUI
 //Window input(){
 input(Window& r){ 
  //Window w;
  //...
  cout << "请输入窗口标题、xy坐标、宽度高度:\n";
  cin >> r.text >> r.x >> r.y >> r.width >> r.height;
  
  return w;
 
 }
 void print(const Window& r)
 {
  cout << "========" << r.text << "=========" endl;
  cout <<"从(" << r.x << ',' << r.y <<")到(" << r.x + r.witdh << ',' << r.y + r.height <<")"\n;
 }
 int main()
 {
  int m=10;n=20;
  JiaoHuan(&m,&n);//通过地址来交换值
  cout << m << ',' << n << endl;
  JiaoHuan(m,n);////实参初始化形参,引用是用谁初始化就是谁的别名或引用
  cout << m << ',' << n << endl;
  void(*p)(int &,int &)=&JiaoHuan;//孤立的去看函数的地址是没有意义的,必须看其赋值给谁
  p(m,n);
  cout << m << ',' << n << endl;
  cout <<"&m=" << &m << ",&n=" << &n << endl;
  print(m);
  print(n);
  print(123);
  print(m+n);//保存在临时空间,在上面需要加const限制;
  //写一个函数让用户来输入窗口的信息
  
  Window w;
  input(w);
  print(w);
 }
 //在上面的例子中有多个JiaoHuan函数只是形参类型不同(函数重载);c语言中是没有的;但是c++,java中有
 //函数形参尽量用引用;数组和基本类型尽量不要用引用。
 //如果不用引用,基本上可以理解为把数值再复制一份,而不是原始数据
 //如果引用不加const,意味着可能要改变引用变量的值
 
 比较下列两个例子
 #include <iostream>
 using namespace std;
 
 int max(int x,int y)
 {
  return x<y?y:x;
 }
 int main()
 {
  int m=10,n=20;
  max(m,n);//返回的是值而不是变量
 }
 //没有引用的时候只是把return返回值复制一份回来放到临时空间中作为结果
 
 
 
 #include <iostream>
 using namespace std;
 
 int& max(int& x,int& y)
 {
  return x<y?y:x;
 }
 int & counter()
 {
  int cnt=0;
  ++cnt;
  return cnt;
 }
 int main()
 {
  int m=10,n=20;
  max(m,n);//返回的是变量
  max(m,n)+=80;
  cout << m << ',' << n << endl;
  counter()=1000;
 }
 
 
 函数可以重载,多个函数可以使用同一个名字,但是必须要通过参数列表能区分是哪个函数
 
 定义3个函数按照特定的格式来输出数组元素
  int a[5]={11,22,33,44,55};
  print(a,5,); //11 22 33 44 55
  print(a,5,','); //11,22,33,44,55,
  print(a,5,true);//[11 22 33 44 55]
  
 
 #include <iostream>
 using namespace std;
 
 void print(int a[],int n)//extern "C" void printf(int a[],int n)//意思是在编译的时候不要改变函数的名字
 {
  for (int i=0;i<n;i++)
   cout << a[i] << ' ';
  cout << endl;
 }
 void print(int a[],int n, char sep)
 {
  for(int i=0;i<n;i++)
   cout << a[i] <<sep;//(i=n-1?'\n':sep);
  cout << endl;
 }
 void print(int a[],int n,bool bra)
 {
  if(bra) cout << '[';
  if (n>0) cout << *a;
  for(int i=1;i<n;i++)
   cout << ' ' << a[i];
  if (bra) cout << ']';
  cout << endl;
 }
 
 
 int main()
 {
  int a[5]={11,22,33,44,55};
  print(a,5,); //11 22 33 44 55
  print(a,5,','); //11,22,33,44,55,
  print(a,5,true);//[11 22 33 44 55]
  
 }
 
 
 变更理解
 
 #include <iostream>
 using namespace std;
 
 void print(int a[],int n, char sep)
 {
  if(bra) cout << '[';
  if (n>0) cout << *a;
  for(int i=1;i<n;i++)
   cout << ' ' << a[i];
  if (bra) cout << ']';
  cout << endl;
 }
 void print(int a[],int n)//extern "C" void printf(int a[],int n)//意思是在编译的时候不要改变函数的名字
 {
  print(a,n,' ',false)
 }

 void print(int a[],int n,bool bra)
 {
  print(a,n,sep,false)
 }
 
 
 int main()
 {
  int a[5]={11,22,33,44,55};
  print(a,5,); //11 22 33 44 55
  print(a,5,','); //11,22,33,44,55,
  print(a,5,true);//[11 22 33 44 55]
  
 }
 
 
 
 
 //可以将以上函数简化成
 void print(int a[],int n,char sep=' ',bool bra=false)
 {
  
 }
 //c++,函数的形参可以带默认值,如以上的char sep=' ',bool bra=false;有默认值的形参只能在最后摆放
 //默认值在声明中指定
 
 
 void f(int);//A
 void f(int,bool=true);//B
 
 f(20);//这样的话编译器会报错。
 
 
 
 #include <iostream>
 using namespace std;
 
 int f(int a){return a*a;}
 int f(int a,int b){return a*b;}
 int main()
 {
  cout << f(10) << endl;
  cout << f(12,34) << endl;
 }
 
 
 inline,经过分析之后做代码的替换;inline只是一个请求,具体做不做不是他的事
 
 
 宏函数不需要时间和空间,不是真正的函数,而是用一组代码替换相应的内容;如果参数里面有a++之类的就会异常出错。
 在c++里面提供了一种更好的处理机制,inline,功能类似宏,但是不是原始替换。===》称做“内联函数”
 (机器指令的替换而非代码的替换)、
 
 c++不提倡用宏,尽量不要用宏。(至少宏里面没有类型检查)
 
 
 #include <iostream>
 using namespace std;
 
 inline void f1(){cout << "call f1\n";}
 inline int f2(int n){return n*n; }
 inline int f3(int n){if (n<2) return 1;return n*f3(n-1);}
 int main()
 {
  f1();
  f2(10);
  f3(6);
  cout << f2(10)+f3(6) << endl;
 }
 
 面向过程:关注过程步骤细节
 面向对象:一切以对象为为目标  object-oriented. OOA,OOP,OOD
 
 struct A
 {
  void f(){}
 
 }
 
 
 vi object.cpp
 #include <iostream>
 using namespace std;
 #include <string>
 int main()
 {
  string s="hello world";//string 类,s对象
  //string s("hello world");与上面等价,括号更加方便
  s.replace(2,5,"XXXX");
  s.insert(1,"ilove")
  cout << s << endl;
  //cout.operator <<(s);
 }
 
 vi class.cpp
 #include <iostream>
 #include <string>
 using namespace std;
 
 struct PS{
  string name;
  int age;
  void show(){cout << " i am " << name << ",age" << age <<endl;}
 };//成员默认都是公开的
 class PC{
  string name;
  int age;
 public://可以将其公开
  void show(){cout << " i am " << name << ",age" << age <<endl;}
  PC(const char* n,int a){name=n;age=a;}//与类同名的函数
 };//公开方法,保护数据
 
 int main()
 {
  PS s={"jy",6};//初始化
  PC c("yj",30);//初始化,数据先放到一个PC(const char *n,int a){}函数的形参中
  //PC d;//编译错误,保证对象里面没有垃圾数据
  //s.name="jy";//可以;//c里面没有什么私有的,一切都是公开的
  //c.name="yj";//编译错误;不允许直接访问数据;默认私有的
  s.show();
  c.show();
 }
 
 创建对象只把数据传到构造函数,
 
 
 
 写这么一个类
 class Time{
  int h;
  int m;
  int s;
 public:
  Time(){}
  Time(int xs,int fz,int ms){}
  void show();
  void tick();
 }
 
 int main()
 {
  Time t1;
  Time t2(16,23,39);
  t1.tick();
  t2.tick();
  t1.show();
  t2.show();
 }
 
 
 vi time.cpp
 #include <iostream>
 using namespace std;
 class Time{
  int h;
  int m;
  int s;
 public:
  Time(){h=m=s=0;}
  Time(int h,int m,int s){Time::h=h;Time::m=m;Time::s=s;}
  void tick(){
   if(++s>=60){
    s=0;
    if(++m>=60){
     m=0;
     if(++h>=24){
      h=0;
     }
    }
   }
  }
  void show(){
   cout << h<< ':' << m << ':' << s << endl;
  }
 };
 int main()
 {
  Time t1;
  Time t2(16,49,58);
  t1.tick();
  t2.tick();
  t1.show();
  t2.show();
  
 }
 
 
 
 class Date{
  int y,m,d;
 public:
  Date(int y=1970,int m=1,int d=1;)//默认值
  void go();
  void show();
  void input();
  int weekday();
  int difference(Date d2);
  void printMonth();
 }