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();
}