c++基础知识笔记一
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();
}