基本部分:
1、ctrl+f5 調試不運行,會出現press anykey to continue
f5 調試
2、c++變c,修改Stdafx.h,將#include<stdio.h>替換為#include<iostream>
在主函數源文件中加入using namespace std;
數據類型
3、關於字符型變量。
input:
char a=10;
int b=a+'\a';
output:b=17。
但是字符型的輸出不是整數,而是該整數所代表的ASCII碼字符。
input:
char a=65;int b=65;
cout<<a<<" "<<b<<endl;
output:
a 65
4、關於常量,可用預處理命令,宏#define,也可用const定義。
#define LIYAKUN 130
const int liYaKun=130;
基本結構:
5、關於main函數
存在int main(int argc,char *argv),arge表示有多少個參數被傳遞給主函數,argv[]表示參數以字符串數組的形式來傳遞。
不存在void main(),main函數存在Int型的返回值。
6、輸入輸出cin<<,cout>>.
cin需要先按下enter鍵,然後才處理來自鍵盤的輸入。
運算符:
7、C++中存在>=,<=,為關系運算符。
數組:
8、篩選法。可以通過較小的復雜度篩選出兩組混雜的數據。
函數:
9、聲明要放在頭文件中,可以使被調函數與所有聲明保持一致,如果函數接口發生變化,只需要修改唯一的聲明。
10、形參在函數調用結束後,形參分配的空間即被釋放。
11、值傳遞是無法實現其功能。
void swap(int a,int b)
{
int temp;
temp=a;
a=b;
b=temp;
}
12、int _tmain(int argc, _TCHAR* argv[])可以兼容main()。
13、內聯函數inline可以減少函數調用時間,因為inline在編譯時,在調用處直接用函數體進行替換。減少了普通函數在掉那樣時的棧內存的創建和釋放的開銷。
但是inline不能用循環、If語句,且必須要簡潔。
#include "stdafx.h"
using namespace std;
inline int swap(int a,int b);
inline int swap(int a,int b)
{
int temp;
temp=a;
a=b;
b=temp;
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
cout<<swap(1,2)<<endl;
return 0;
}
指針:
14、指針運算符*,在定義的時候稱為指針定義符,此時和指針運算符號的意義完全不同。它的作用是表示所聲明的變量的數據類型是一個指針。
int _tmain(int argc, _TCHAR* argv[])
{
int iValue=10;
int *iPtr=&iValue;
cout<<&iPtr<<endl;
cout<<iPtr<<endl;
cout<<*iPtr<<endl;
}
output:
0071F938
0071F938
10
15、指向函數的指針。實際上是指向存儲函數代碼的首地址。
定義格式如:數據類型 (* 函數指針名)(形參表);
注意:為了與返回指針的函數進行區別,第一個括號不能省略。
在C++中,賦值的格式如:函數指針名(參數表);
注意:函數指針變量不能進行算數運算,毫無意義。
16、動態內存的分配方式。
堆和棧:1)大小。棧是由系統自動分配的連續的地址空間,1M~2M。堆是通過鏈表來存儲的空閒內存地址,受限於系統的虛擬內存,但遠遠大於棧的內存。2)棧主要是由局部變量,函參。堆是由程序員自行分配的內存區域。因此,棧的空間由系統自動釋放,堆的空間由程序員釋放。
動態內存的分配:1)可用鏈表。也就是堆的方式。屬於C++的方式。2)可用malloc等函數分配。是自由存儲區的方式。屬於C的方式。
比較直觀的感覺:當進行數組讀寫時,動態數組的下標可以用變量來表示。
17、C++動態內存的分配。
格式:new 類型名(初始值);如:pnValue=new int(3);//通過New分配了一個存放int類型的內存空間,並且將這個內存上寫初始值3。
注意:如果開辟動態內存,一定要判斷是否開辟成功。
如:int _tmain(int argc, _TCHAR* argv[])
{
int *pnValue;
pnValue=new int(3);
if (pnValue==NULL) exit(1);//如果內存開辟失敗,指針為NULL
else
cout<<"Success!"<<endl;
}
18、C++動態內存的賦值。
當申請空間為數組時,為其賦值不要用指針計算,如“pnValue++;”因為存儲地址不是連續的,因此當退回時會出現錯誤。正確的方法是用過下標或者臨時指針來訪問動態數組。
下標:int _tmain(int argc, _TCHAR* argv[])
{
int *pnArray=new int[5];
pnArray[0]=1;
pnArray[1]=2;
}
臨時指針:int _tmain(int argc, _TCHAR* argv[])
{
int * pnArray=new int[5];
int * pnArrayMove=pnArray;
* pnArrayMove=1;
pnArrayMove++;
* pnArrayMove=2;
}
19、C++初始化動態數組。可用memset函數快速賦值
格式:memset(指針名,初始化值,開辟空間的總字節數)
如:int _tmain(int argc, _TCHAR* argv[])
{
long *plArray=new long[4];
memset(plArray,0,sizeof(long)*5);//sizeof()不能計算動態內存容量
}
20、C++動態內存的釋放。
在C中我們用malloce申請,然後用free釋放。在C++中我們用new來申請,用delete釋放。同樣,在釋放以後,我們需要把這些指針賦值NULL。
delete a;//a是動態內存變量
delate[] a;//a是動態內存數組
如:int _tmain(int argc, _TCHAR* argv[])
{
long *plArray=new long[10];//申請
meset(plArray,0x00,sizeof(long)*10);//初始化
delete[] plArray;//釋放
plArray=NULL;//賦值NULL
}
引用:
21、引用時一個變量或者對象的別名。格式如下:數據類型& 所引用變量或對象名(目標變量或對象)。
如:int _tmain(int argc, _TCHAR* argv[])
{
int nValue;
int& rValue=nValue;
return 0;
}
22、當引用作為函數參數出現時的情況。
在函數被調用時,由於引用函數作為函數參數出現,因此系統在函數體中直接改變實參,這點跟指針的效果一樣。這是引用出現的最常見的情況。
如:void swap(int& a,int& b)
{
int temp;
temp=a;
a=b;
b=temp;
}
int _tmain(int argc, _TCHAR* argv[])
{
int nValueA=10;
int nValueB=20;
int& rValueA=nValueA;
int& rValueB=nValueB;
cout<<nValueA<<","<<nValueB<<endl;
swap(rValueA,rValueB);
cout<<rValueA<<","<<rValueB<<endl;
return 0;
}
輸出:10,20
20,10
注意:此時,由於函數體改變了引用,。,nValueA=20,nValueB=10。
!! 注意:引用的格式,必須為(類名& 實例名)!空格不能亂加。
!!類名& 函數體(參數),含義是返回一個類的引用。類的實參返回。
共用體:
23、與結構體類型不同的是,共用體的提點1)同一共用體成員共用一個存儲區,存儲區大小等於最長字節的成員。2)同一時刻,在一個共用體變量中,只有一個成員起作用。
字符串:
24、sizeof()是操作符,用來返回類型的大小,包括\0,strlen()是函數,用來返回字符串的長度,其中不包括\0。
25、cin.getline(數組名稱,讀取字符數);這個函數讀取一行,直至達到換行符,作為字符串的邊界。
類:
26、類是C++封裝的基本單位,它把數據和函數封裝在一起。在定義一個類後,可以聲明一個類的變量,即類的對象或者實例。
class 類名
{
…
};
命名類的時候加前綴"C"。
27、在定義類的時候,不為類分配存儲空間,不能為類中的數據初始化。
28、成員函數。在類中被聲明:
class 類名{
訪問控制關鍵字 返回值類型 成員函數名(參數表);
};
訪問控制關鍵字:public/private(default)/protected,因為如果不對其進行設置,系統會默認設置,所以在定義時需要定義它的訪問控制字。
如下:
class math(){
public: //習慣性先設置公共部分
void abs();
void add();
void mul();
private:
string number_1;
string number_2;
};
29、成員函數在類外實現。
class Cmath{
void abs();
}
void Cmath::abs(){
cout<<"Success!"<<endl;
};
30、類的實例,也稱對象。當實例為非指針時,訪問格式為“實例.類成員”;當實例為指針時,范根格式為“實例指針->類成員”。
如:
math HighMath;
math *pHighMath;
pHighMath=&HighMath;
pHighMath->study();
31、靜態數據成員。
當數據在類中聲明為private控制型,但在程序過程中需要對它進行修改。此時可以加static來任何類的實例都可以對其數據進行改變。靜態數據不屬於任何一個實例,只能通過類名來訪問。
格式為:int CMath::jingtaishuju=0;
不僅可以在main.cpp中訪問,也可以在類實現文件中訪問。
32、靜態成員函數。
在1)沒有實例生成時就需要訪問類中的函數信息2)需要所有的類和對象都能訪問時,用靜態函數。
定義格式:
static 返回值類型 成員函數名(參數表)
訪問格式:
類名::成員函數名
構造函數
33、構造函數。構造函數實現在實例被創建時利用特定的值去構造實例,將新建的實例初始化為一個特定狀態。
構造函數屬於類裡面的一個特殊的類,由系統自動調用,定義時無返回值。
格式:
類名();//構造函數名與類名相同
34、帶參數的構造函數。帶參數的構造函數需要用實參來進行賦值。
!!注意,帶參數的構造函數和不帶參數的構造函數可以同時存在,相當於構造函數的重載,可8以不帶參數賦默認值,也可以帶參數,先賦默認值,再賦參數。
所以!最好在每次定義的時候都要寫上不帶參數的構造函數!
這個地方容易產生很多錯誤,錯例如下:
Cmath xianxingdaishu;
xianxingdaishu.Cmath(1,2,3);
//錯誤!系統會在第一行語句中默認為,使用默認構造函數,因為構造函數是一直存在的。已經產生了實例以後,這樣賦值就是不對的。
如果構造函數要包含參數,就必須在定義的時候給出實參,實參甚至可以不用定義。
改為:
Cmath xianxingdaishu(1,2,3);//此處Cmath不是類名,而是構造函數名。
格式:
類名(初始化參數表);
35、拷貝構造函數。
用一個實例構造另一個實例,使其初始化為與原實例相同的數據,用拷貝構造函數。可以理解為,構造函數為類的一個特殊函數,拷貝構造函數為構造函數的一個特殊例子。拷貝構造函數與構造函數並存。
聲明格式:
類名(類名& 實例名)//這裡的實例名實際上就是參數名,形參
實現格式:
類名::拷貝構造函數名(類名& 實例參數)//實例參數:形參
36、何時應該聲明類頭文件?
只在類.cpp和主函數.cpp中聲明 類.h。
37、默認拷貝構造函數。
如果不寫拷貝構造函數,直接在定義的時候對其進行賦值初始化:
如:
//CMath.h
class CMath{
public:
CMath(string strMathName,string trMathLength,float strMathLevel);//構造函數
//CMath(CMath& MathModel);//拷貝構造函數
void SetMathName();
void SetMathLength();
void SetMathLevel();
void ShowMathName();
void ShowMathLength();
void ShowMathLevel();
private:
string m_strMathName;
string m_strMathLength;
float m_fMathLevel;
};
//CMath.cpp
CMath::CMath(string MathName,string MathLength,float MathLevel){
m_strMathName=MathName;
m_strMathLength=MathLength;
m_fMathLevel=MathLevel;
};
//主函數
#include "stdafx.h"
using namespace std;
#include "CMath.h"
#include "string.h"
int _tmain(int argc, _TCHAR* argv[])
{
CMath MathModel1("FFT","fifty",8);
CMath MathModel2=MathModel1;//調用了默認的拷貝構造函數
MathModel2.ShowMathName();
MathModel2.ShowMathLength();
MathModel2.ShowMathLevel();
}
實際相當於,將所有的非靜態變量都賦值給了新定義的實例。
38、默認拷貝構造函數的局限。
1)默認,是完全相同的賦值,實際上很多時候是不必要的。
2)無法實現對動態內存進行拷貝。
39、fatal error LNK1120: 1 個無法解析的外部命令。
因為在頭文件已經聲明,但是在CPP文件中沒有實現。
40、深拷貝。由於存在默認拷貝構造函數的局限性,尤其是在對類中存在動態內存時無法拷貝,深拷貝能完成動態內存的拷貝。
原理,在類中增加深拷貝函數,函數實現中先進行另外一個動態內存申請,然後再賦值。
如:
//CMath.h
class CMath{
public:
CMath(string strMathName,string trMathLength,float strMathLevel);//構造函數
CMath(CMath& MathModel);//拷貝構造函數,深拷貝
void SetMathName();
void SetMathLength();
void SetMathLevel();
void ShowMathName();
void ShowMathLength();
void ShowMathLevel();
private:
string * m_strMathName;//在實現函數中對其進行賦初值,new string
string m_strMathLength;
float m_fMathLevel;
};
//CMath.cpp
CMath::CMath(string MathName,string MathLength,float MathLevel){
m_strMathName=new string;//動態賦初值
*m_strMathName=MathName;
m_strMathLength=MathLength;
m_fMathLevel=MathLevel;
};
CMath::CMath(CMath& MathModel){//建立拷貝構造函數
m_strMathName=new string;//再開動態賦初值
*m_strMathName=*MathModel.m_strMathName;
m_strMathLength=MathModel.m_strMathLength;
m_fMathLevel=MathModel.m_fMathLevel;
};
//主函數
int _tmain(int argc, _TCHAR* argv[])
{
CMath MathModel1("FFT","fifty",8);
CMath MathModel2(MathModel1);//引用已定義的實例
MathModel2.ShowMathName();
MathModel2.ShowMathLength();
MathModel2.ShowMathLevel();
}
41、析構函數。對當前分配的資源進行清理。
聲明語法格式:~類名()//virtual ~CMath();//虛析構函數
實現如:CMath::~CMath()
{
delete m_strMathName;
m_strMathName=NULL;
}
注意:析構函數是默認存在的,程序員需要設置對其類中包含的動態變量進行析構。
!!在主程序中不需要調用析構函數,因為系統會在實例的生存期結束以後自動調用類中的析構函數。
!!一旦聲明了析構函數,就必須對析構函數進行實現!
42、類的組合。
類的組合其實就是在類的聲明裡面嵌套其他的類。類的組合主要問題在於初始化,因為要同時對類的內嵌對象進行初始化。
格式:類名::類名(形參表):內嵌對象1(形參表),內嵌對象2(形參表)
{
}
//這個地方還有不清楚的地方。
友元函數和友元類
43、友元就是在需要訪問多個類的私有參數時,用到了友元。但是在可以利用關鍵字friend來修飾。包括友元函數,友元類(類中所有函數都是友元函數)。
聲明格式:friend 返回值類型 函數名(參數);
//EleSchStu.h
class EleSchStu{
public:
void SetName(EleSchStu &);
virtual ~EleSchStu();
//設置友元函數來測試名字長度,不一定非要是引用型
friend void CheckNameLength(EleSchStu &);
private:
string strName;
static const int MAX_NAME_LEN;
double score1;
double score2;
double score3;
};
//EleSchStu.cpp
#include "stdafx.h"
using namespace std;
#include "EleSchStu.h"
#include <string>
void EleSchStu::SetName(EleSchStu &xiaoming){
string str;
cout<<"input the name:"<<endl;
cin>>str;
xiaoming.strName=str;
};
EleSchStu::~EleSchStu(){
};
void CheckNameLength(EleSchStu &xiaoming){
if ((xiaoming.strName.length())>xiaoming.MAX_NAME_LEN)
{
cout<<"輸入的名字長度太長了!"<<endl;
}
};
//主函數
const int EleSchStu::MAX_NAME_LEN=3;
const int JuniorSchStu::MAX_NAME_LEN=3;
int _tmain(int argc, _TCHAR* argv[])
{
EleSchStu xiaoming;
xiaoming.SetName(xiaoming);
CheckNameLength(xiaoming);
return 0;
}
44、include <string>
重載----重載函數和運算符重載
45、重載函數。允許用同一個函數名定義多個函數,簡化程序設計。從而使一個函數名就可以完成一系列相關的任務。
重載函數如下一組:
long abs(long);
double abs(double);
注意!只有是返回類型、參數類型、參數個數、參數順序上有所不同!不能僅僅是返回值不同。否則不能識別為重載函數。
46、運算符重載。(operator)
對已有的運算符賦予更多的含義。如:使同一個運算符作用於不同類型的數據。(運算符:+,-,*,/,%,new等)
當運算符重載為成員函數時://關鍵字 operator
格式:函數類型 operator 運算符 (形參表)
{
函數體;
}
為類的友元函數時:
格式: friend 函數體 operator 運算符(形參表)
{
函數體:
}
47、轉換運算符的重載。
當用戶自定義的數據類型也需要支持數據的轉換時,需要用重載轉換運算符。而且不能是友元函數。
格式如下:
operator 類型名();//返回類型其實就是類型名,所以不需要制定返回類型。
48、賦值運算符的重載。
關於重載的實例:
需求:寫出復數的+、-、*,用類的重載實現,分別用三個友元函數實現運算,能夠顯示原數據,最終分別用實例來驗證三個算法。
//CComplex.h
#include <iostream>
using namespace std;
//CComplex.h
class CComplex
{
public:
CComplex();//不帶參數的構造函數
CComplex(double temp_real,double temp_imag);//含參的構造函數
virtual ~CComplex();
void show();
private:
double real;
double imag;
friend CComplex operator + (CComplex a,CComplex b);
friend CComplex operator - (CComplex a,CComplex b);
friend CComplex operator * (CComplex a,CComplex b);
};
//CComplex.cpp
#include <iostream>
using namespace std;
#include "stdafx.h"
#include "CComplex.h"
CComplex::CComplex()
{
cout<<"默認構造函數……"<<endl;
real=0;
imag=0;
}
CComplex::CComplex(double temp_real,double temp_imag)
{
real=temp_real;
imag=temp_imag;
}
CComplex::~CComplex()
{
}
void CComplex::show()
{
cout<<"("<<real<<","<<imag<<")"<<endl;
}
CComplex operator + (CComplex a,CComplex b)
{
CComplex plus;
plus.real=a.real+b.real;
plus.imag=a.imag+b.imag;
return plus;
}
CComplex operator - (CComplex a,CComplex b)
{
CComplex minus;
minus.real=a.real-b.real;
minus.imag=a.imag-b.imag;
return minus;
}
CComplex operator * (CComplex a,CComplex b)
{
CComplex mult;
mult.real=a.real*b.real-a.imag*b.imag;
mult.imag=a.real*b.imag+a.imag*b.real;
return mult;
}
//重載.cpp
#include "stdafx.h"
#include "CComplex.h"
int _tmain(int argc, _TCHAR* argv[])
{
CComplex p1(1.0,2.0);
CComplex p2(3.0,4.0);
CComplex p3,p4,p5;
p3=p1+p2;
p4=p1-p2;
p5=p1*p2;
p1.show();
p2.show();
cout<<"+:";
p3.show();
cout<<"-:";
p4.show();
cout<<"*:";
p5.show();
return 0;
}
繼承和派生:
49、派生類。
派生會接收基類中除了構造函數和析構函數以外的所有成員。也可以改造基類成員,對其進行覆蓋和重載,也可以增加新的類成員。
格式:
class 派生類名:繼承方式 基類名1,繼承方式 基類名2…
//!繼承只有一個冒號!
{
成員聲明;
}
// 繼承方式的關鍵字:public/protected/private(default)
50、繼承中的訪問控制。
為public繼承時,基類中保護成員和公有成員在派生類中不變。
為private繼承時,基類中保護成員和公有成員在派生類中變為私有成員。(由於會中止類的繼續派生,因此Private繼承基本沒用)
為protected繼承時,基類中保護成員和公有成員在派生類中變為保護成員。(在protected繼承中,基類中的protected成員在基類的派生中的訪問權限還是protected;在private繼承中,基類中的protected成員在基類的派生中訪問權限是private,因此在下一級的派生中,就無法訪問基類的成員!!因此protected繼承更加適合多層派生!!)
!!所有的繼承均無法訪問基類中的私有成員。
!!!Protected 與Public有區別!!protected是保護的,只有他自身或者繼承他的類可以用,public是共有的,在靜態下所有類都可以通過類名打點調用,不是靜態下,可以用類對象點去調用。
!!!???
如例:
#include "stdafx.h"
//Point.h
class CPoint
{
public:
//CPoint();//構造函數
virtual ~CPoint();
void InitPoint(double x,double y);
double GetX();
double GetY();
protected:
double X,Y;
};
#endif
//Linesegment.h
#include "stdafx.h"
#include "CPoint.h"
class CLinesegment:protected CPoint
{
public:
//CLinesegment();
virtual ~CLinesegment();
void InitLinesegment(double x,double y,double length);
double GetX();//可以直接訪問基類的保護成員
double GetY();//可以直接訪問基類的保護成員
double GetLength();
protected:
//double X,Y;
double Length;
};
//CPoint.cpp
#include "stdafx.h"
#include "CPoint.h"
//#include "Linesegment.h"
CPoint::~CPoint()
{
};
void CPoint::InitPoint(double x,double y)
{
this->X=x;
this->Y=y;
};
double CPoint::GetX()
{
return this->X;
};
double CPoint::GetY()
{
return this->Y;
};
//Linesegment.cpp
#include "stdafx.h"
#include "CPoint.h"
#include "Linesegment.h"
CLinesegment::~CLinesegment()
{
};
void CLinesegment::InitLinesegment(double x,double y,double length)
{
InitPoint(x,y);//調用基類的函數
this->Length=length;
};
double CLinesegment::GetX()//可以直接訪問基類的保護成員?????,因為繼承類中不存在x,y的成員變量
{
return this->X;
};
double CLinesegment::GetY()//可以直接訪問基類的保護成員?????,因為繼承類中不存在x,y的成員變量
{
return this->Y;
};
double CLinesegment::GetLength()
{
return this->Length;
};
//主函數
// 保護繼承.cpp : 定義控制台應用程序的入口點。
#include "stdafx.h"
#include "CPoint.h"
#include "Linesegment.h"
int _tmain(int argc, _TCHAR* argv[])
{
CLinesegment L1;
L1.InitLinesegment(0,0,5);
cout<<"("<<L1.GetX()<<","<<L1.GetY()<<","<<L1.GetLength()<<")"<<endl;
return 0;
}
51、派生類的構造函數。
由於派生類不能繼承基類的構造函數,因此需要定義構造函數。
聲明格式: 構造函數(參數);
實現格式:派生類名::派生類名(參數):繼承方式1 基類名1(參數表1),繼承方式2 基類名2(參數表2)...,內嵌實例名1(參數表1)//內嵌就是在派生類中又定義的類
{
派生類構造函數函數體;
}
!如果基類中沒有自定義的構造函數,就將基類名(參數表)省略。所有都可以省略時,可以用生兩側派生類構造函數的成員初始化列表。
52、派生類的析構函數。
直接析構。
53、派生類成員的標識和訪問。
格式:派生類實例名.基類名::成員名;
派生類實例名.基類名::成員函數名(函數表);
::是作用域分辨符,可以用於限定要訪問的成員所在的類的名稱。
!::不可以嵌套使用,比如:實例A.C1::C2::fun();錯誤!只能在C2函數中聲明fun1(){},再調用fun()。
54、虛基類:解決二義性的問題。
聲明格式:class 類名: virtual 繼承方式 基類名。
實例:定義一個車的基類,有最大速度、質量成員變量,及一些成員函數;派生出自行車類和汽車類,自行車有高度等成員變量,汽車有座位數等成員變量;從自行車和汽車派生出摩托車類。要求觀察析構函數的執行和繼承中,把車類設成虛基類和不設為虛基類的區別。
//vehicle.h
#ifndef _vehicle_h_
#define _vehicle_h_
#include "stdafx.h"
class CVehicle
{
public:
CVehicle();
CVehicle(int speed,int weight);
virtual ~CVehicle();
protected:
int Speed;
int Weight;
};
#endif
//vehicle.cpp
#include "stdafx.h"
#include "vehicle.h"
CVehicle::CVehicle()
{
cout<<"CVehicle類的實例的構造函數生成!"<<endl;
};
CVehicle::CVehicle(int speed,int weight)
{
this->Speed=speed;
this->Weight=weight;
}
CVehicle::~CVehicle()
{
cout<<"CVehicle類的實例的析構函數生成!"<<endl;
};
//bike.h
#ifndef _bike_H_
#define _bike_H_
#include "stdafx.h"
#include "vehicle.h"
class CBike:virtual public CVehicle
{
public:
CBike();
CBike(int height);
virtual ~CBike();
protected:
int height;
};
#endif
//bike.cpp
#include "stdafx.h"
#include "vehicle.h"
#include "bike.h"
CBike::CBike()
{
cout<<"CBike類的實例的構造函數生成!"<<endl;
};
CBike::CBike(int height)
{
this->height=height;
}
CBike::~CBike()
{
cout<<"CBike類的實例的析構函數生成!"<<endl;
};
//car.h
#ifndef _car_H_
#define _car_H_
#include "stdafx.h"
#include "vehicle.h"
class CCar:virtual protected CVehicle
{
public:
CCar();
CCar(int seat);
virtual ~CCar();
protected:
int seat;
};
#endif
//car.cpp
#include "stdafx.h"
#include "vehicle.h"
#include "car.h"
CCar::CCar()
{
cout<<"CCar類的實例的構造函數生成!"<<endl;
};
CCar::CCar(int seat)
{
this->seat=seat;
};
CCar::~CCar()
{
cout<<"CCar類的實例的析構函數生成!"<<endl;
};
//motor.h
#ifndef _motor_H_
#define _motor_H_
#include "stdafx.h"
#include "vehicle.h"
#include "bike.h"
#include "car.h"
class CMotor: public CBike,public CCar
{
public:
CMotor();
CMotor(int speed, int weight, int height, int seat, int money):CVehicle(speed,weight),CCar(seat),CBike(height)
{
this->money=money;
};
virtual ~CMotor();
void showMotor();
protected:
int money;
};
#endif
//motor.cpp
#include "stdafx.h"
#include "vehicle.h"
#include "car.h"
#include "bike.h"
#include "motor.h"
CMotor::CMotor()
{
cout<<"構造CMotor類的實例!"<<endl;
}
CMotor::~CMotor()
{
cout<<"CMotor類的實例的析構函數生成!"<<endl;
}
void CMotor::showMotor()
{
void showCar();
void showBike();
//showVehicle();
cout<<"speed="<<this->Speed<<endl;
cout<<"weight="<<this->Weight<<endl;
cout<<"height="<<this->height<<endl;
cout<<"seat="<<this->seat<<endl;
cout<<"money="<<this->money<<endl;
}
//主函數
// 繼承.cpp : 定義控制台應用程序的入口點。
#include "stdafx.h"
#include "vehicle.h"
#include "car.h"
#include "bike.h"
#include "motor.h"
int _tmain(int argc, _TCHAR* argv[])
{
int a=200,b=50000,c=1,d=4,e=100000;
CMotor motor(a,b,c,d,e);
motor.showMotor();
return 0;
}
55、多態性
指同一個函數,根據處理的對象不同,所調用的函數實現不同。通過虛函數來實現。
56、虛函數。
當基類定義的一個函數,派生類對函數進行了重載。重載以後,程序無法確定到底是哪個類調用了函數。
當然,我們可以用作用域運算符來確定到底是哪個調用了。但有的情況下,程序會不知道:聲明的函數到底調用了基類的對象,還是派生類的對象。因此,程序會默認調用了基類的對象,導致邏輯錯誤。
!一句話概括:在基類的函數前加上virtual關鍵字,在派生類中重寫該函數,運行時將會根據對象的實際類型來調用相應的函數。如果對象類型是派生類,就調用派生類的函數;如果對象類型是基類,就調用基類的函數。
虛函數定義格式:
virtual 函數返回格式 函數名()
{
};
調用格式():
Class CA
{
public:
…
virtual float xuhanshu()
{};
}
Class CB:public CA
{
public:
...
virtual float xuhanshu()
{};
}
//mian.cpp
float get_xuhanshu(CA& temp)//注意參數類型
{
return temp.xuhanshu();
}
main()
{
CA test1;
CB test2;
get_xuhanshu(test1);//系統識別調用CA中的實例
get_xuhanshu(test2);//系統識別調用CB中的實例
}
57、純虛函數和抽象類。
純虛函數就是在一般的虛函數定義的後面加“=0”,本質上是將指向函數體的指針置零。
抽象類是帶有純虛函數的類。抽象類的作用是為了建立類族的共同接口。抽象類不能實例化,但抽象類的派生類可以實例化。
抽象類中的純虛函數可以在主函數中實現,然後它的引用可以被任何派生類的實例調用。
如:
class A
{
...
virtual void display()=0;
...
}
class B:A
{
...
virtual void display()
{ cout<<"class B"<<endl;};
...
}
class C:B
{
...
virtual void display()
{ cout<<"class C"<<endl;};
...
}
//main.cpp
void display(A& temp)
{
temp.display();
}
void main()
{
B b;
C c;
display(b);//相當於在主函數中聲明了一個函數,只要是A類族的參數都可以調用。
display(c);
}
output:
class B
class C
例子:抽象類shape,5個派生類,circle,square,rectangle,trapezoid,triangle,用虛函數分別計算幾個圖形面積,並求它們的和。用基類指針數組,使它的每一個元素指向一個派生類對象。
//shape.h
#ifndef _Shape_H_
#define _Shape_H_
#include "stdafx.h"
class Shape
{
public:
virtual void show(){};
virtual double area()=0;//只有含返回參數的成員函數,才能當作純虛函數
//主要當作一個接口
};
#endif
//circle.h
#include "stdafx.h"
#include "shape.h"
#include <math.h>
class circle:public Shape
{
public:
circle(double temp_r)
{
r=temp_r;
};
virtual ~circle(){};
void show()
{
double temp;
temp=area();
cout<<"this is circle! the area is "<<temp<<endl;
};
double area()
{
double temp;
temp=r*r*3.14;
return temp;
};
protected:
double r;
};
//square.h
#include "stdafx.h"
#include "shape.h"
#include <math.h>
class square:public Shape
{
public:
square(double l)
{
this->l=l;
};
virtual ~square(){};
double area()
{
double temp;
temp=this->l*this->l;
return temp;
}
void show()
{
double temp=this->area();
cout<<"this is square!,the area is "<<temp<<endl;
}
protected:
double l;
};
//main.cpp
// 虛函數.cpp : 定義控制台應用程序的入口點。
#include "stdafx.h"
#include "shape.h"
#include "circle.h"
#include "square.h"
#include <math.h>
int _tmain(int argc, _TCHAR* argv[])
{
circle c(5);
square s(5);
Shape *p[2];
p[0]=&c;//虛基類的實例可以指向派生類的引用
p[1]=&s;
p[0]->show();
p[1]->show();
return 0;
}
輸入輸出體系:
58、流。
流其實形象的比喻了C++中數據傳輸的過程。
流操作包含了許多類。類名包括:ios,istream,ostream...
59、流格式化輸出。
如果需要控制流輸出的格式,如果要控制流輸出的格式。一種用流格式控制符;另一種是利用流類的相關成員函數進行控制。
1)流控制符:
需要定義頭文件<iomanip>;
應用如:
int a=15;
cout<<"十進制"<<dec<<a<<endl;//以十進制形式輸出整數a
cout<<"十六進制"<<hex<<a<<endl;
double pi=3.14;
cout<<"指數形式"<<setiosflags(ios::scientific)<<setprecision(8);
//不需要記住,只需要知道按指數形式輸出,8位小數
2)流控制成員函數。具體應用要具體查文檔。
60、文件操作。
首先需要定義輸入輸出文件流對象頭文件<fstream>。
聲明對象:
ifstream file_in;//建立輸入文件流對象
ofstream file_out;//建立輸出文件流對象
fstream file_inout;//建立輸入輸出文件流對象
構造函數:
ifstream::ifstream(const char*,int=ios::in,int=filebuf::openprot);
ofstream::ofstream(congst char*,int=ios::out,int=filebuf::openprot);
fstream::fstream(cont char*,int,int=filebuf::operprot);
調用構造函數如:
ofstream file_out("C:\\a_out.dat",ios::out|ios::binary);//以二進制方式打開輸出文件。
61、檢查是是否打開文件。關閉文件。
bool fail();//失敗返回true,成功返回false。
類中的成員函數close():
void close();
62、關於寫文件。
分為讀寫字符型文件(主要是讀寫到.txt)和二進制文件(都寫到.dat)。
具體應用如下。
// 打開文件.cpp : 定義控制台應用程序的入口點。
#include "stdafx.h"
#include <iostream>
#include <fstream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
//打開文件!
ofstream file_out;//定義打開文件類
file_out.open("C:\\c++.txt",ios::out|ios::app);//打開文件,用於數據輸出,從文件中寫數據,app是以數據追加方式打開。
if(file_out.fail()) //如果文件打開失敗,則顯示出錯信息。
{
cerr<<"文件 c++.txt 打開失敗!"<<endl;
return 1;
}
//輸出到文件!
//利用插入操作符進行輸出
file_out<<"wo cao ni ma!"<<endl;
file_out<<"我草泥馬!"<<endl;
//利用put()進行輸出
char a = '!';
file_out.put(a);
//文件的內容輸入到內存!
//利用提取操作符
ifstream file_in;//定義打開文件類
file_in.open("C:\\c++.txt",ios::in);//打開文件,用於數據輸入,從文件中讀數據)
if(file_in.fail()) //如果文件打開失敗,則顯示出錯信息。
{
cerr<<"文件 c++.txt 打開失敗!"<<endl;
return 1;
}
char nRead = 0;
while (!file_in>>nRead)//讀取字符,注意,提取的時候是忽略換行和空格字符的
{
cout<<nRead<<" ";//" "即為輸出字符
}
while (!file_in.eof())//讀取字符,注意,提取的時候是包括換行和空格字符的
//eof()用於判斷指針是否已經到文件的末尾了,當返回ture時,已經到達文件的尾部
{
file_in.get(nRead);
cout<<nRead;
}
file_out.close();//關閉文件
file_in.close();
return 0;
}
實例:定義一個結構體,通過鍵盤輸入學生的信息並保存到磁盤stud.dat文件中,並從中讀出來顯示在屏幕上。
// 二進制文件操作.cpp : 定義控制台應用程序的入口點。
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <string>
#include <fstream>
struct Student
{
char name[20];
int age;
char No[20];
char sex[20];
};
int _tmain(int argc, _TCHAR* argv[])
{
Student stu[2];
int i;
int j=0;
for(i=0;i<2;i++)
{
cout<<"please insert your name:";
cin>>stu[i].name;
cout<<"please insert your age:";
cin>>stu[i].age;
cout<<"please insert your Number:";
cin>>stu[i].No;
cout<<"please insert your sex:";
cin>>stu[i].sex;
}
ofstream put_in("C:\\c++.dat",ios::out|ios::binary);//打開二進制文件
if (!put_in) //判斷是否打開成功
{
cerr<<"C:\\c++.dat can't open it..."<<endl;
exit(1);
}
for(i=0;i<2;i++)
{
put_in.write((char *) &stu[i],sizeof(stu[i]));//文件寫入的時候用的是指針,而不是內容
}
put_in.close();
ifstream put_out("C:\\c++.dat",ios::out|ios::binary);//打開二進制文件
if (!put_out)
{
cerr<<"C:\\c++.dat can't open it..."<<endl;
exit(1);
}
for(i=0;i<2;i++)
{
put_out.read((char *) &stu[i],sizeof(stu[i]));//成語按函數read()來讀二進制文件
}
put_out.close();
for(i=0;i<2;i++) //輸出!
{
cout<<"the "<<i+1<<" name:";
cout<<stu[i].name<<endl;
cout<<"the "<<i+1<<" age:";
cout<<stu[i].age<<endl;
cout<<"the "<<i+1<<" Number:";
cout<<stu[i].No<<endl;
cout<<"the "<<i+1<<" sex:";
cout<<stu[i].sex<<endl;
}
return 0;
}
63、異常。
try(){throw 類型名;};
catch(類型變量)
{
};
做過選課系統的應該比較熟悉。
直接上實例。
//MyException.h
#include "stdafx.h"
class CMyException
{
public:
CMyException(string msg)
{
err_msg=msg;
};
virtual ~CMyException()
{
};
void show()
{
cerr<<err_msg<<endl;
}
protected:
string err_msg;
};
//main.cpp
// C++速成.cpp : 定義控制台應用程序的入口點。
//
#include "stdafx.h"
#include "MyException.h"
int _tmain(int argc, _TCHAR* argv[])
{
int type;
cout<<"plese insert the number of exception:1.int 2.float 3.double 4.selfdefine"<<endl;
cin>>type;
try{
switch(type)
{
case 4:
throw CsMyException("wrong!");//拋出自定義類異常
break;
case 1:
throw 1;//整形
break;
case 2:
throw 1.2f;//float
break;
case 3:
throw 1.23;//doubule
break;
default:
break;
}
}
catch(CMyException a)
{
a.show();
}
catch(int b)
{
cerr<<"error int!";
}
catch(float c)
{
cerr<<"error float!";
}
catch(double d)
{
cerr<<"error double!";
}
return 0;
}
API編程:
64、API:Windows Application Programming Interface.
windows底層->win32 API函數->windows應用程序
句柄:本身為內存中一個占有4個字長的數值,用於標識應用程序中不同對象和相同對象的不同實例。句柄與普通指針的區別在於,指針包含的是引用對象的內存地址,而句柄則是由系統所管理的引用標識,該標識可以被系統重新定位到一個內存地址上。這種間接訪問對象的模式增強了系統對引用對象的控制。