目錄
new創建的用delete,但是new []創建的用delete []18
靜態成員函數由於只是和類相關,所以也只能調用靜態成員變量。...18
第一章 數據處理
整形:short(16)、int(16-32)、 long(32) 頭文件limits包含范圍
#include<iostream>
using namespace std;
void main()
{
int int_max = INT16_MAX;
short short_max = SHRT_MAX;
long long_max = LLONG_MAX;
cout<< sizeof short_max <<"\t"<<sizeof(int)<<"\t"<<sizeof long_max<< endl;
}
數據可以大一點就使用unsigned long long
C++用三種基數來表示整數,10,8,16,當然也可以在數字后面加上LU來說明是long和unsigned
#include<iostream>
/*
* they are same
*/
using namespace std;
void main()
{
int eight = 052;
int sixteen = 0x2A;
cout<< ten << "\t" << eight<< "\t" << sixteen << endl;
}
字符型
字符型char
Unsigned char 和signedchar 可以讓char的值從0-255
Float32位 double64 記數可以使用科學計數法3.2E2=320
第二章 復合類型
字符串以’\0’結尾,是字符串類型就發生了取得內存地址的條件,此外char str[6];中
Str=&str[0];所以不可以字符串之間賦值
#include<iostream>
//#include<cstring>
/*
* 字符串賦值的方法有兩種(常用),直接賦值,從鍵盤輸入
*在數組中 str[6], str=&str[0];
*/
using namespace std;
void main()
{
char str1[6] = { 'h','e','l','l','o' };// it is char array
char str2[6] = { 'h','e','l','l','o' ,'\0'};//it is string
char str3[6] = "hello"; //autoto add \0,it is string
char str4[] = "hello"; //it isstring
cout<< "hello""everyone" << endl;//allow to jointstring
}
#include<iostream>
//#include<cstring>
/*
* char[] 以/0結尾,所以在鍵盤進行輸入時有了空格,則以為結束,可以使用cin.getline(city,len),cin.get(city,len)輸入。
*getline()是達到len長度時候結束,或者遇到換行的時候結束。但是get()遇到換行結束,但是可接受換行。
*
*/
using namespace std;
void main()
{
char city[20];
char name[20];
//cin.getline(city,20);cin.getline(name,20);與下一行等效
cin.get(city,20); cin.get(); cin.get(name, 20);
cout<< name<<"\t"<<city<< endl;
}
#include<iostream>
//#include<cstring>
/*strcpy(str1,str2) strcat(str1,str2)
* char[] 以/0結尾,所以在鍵盤進行輸入時有了空格,則以為結束,可以使用cin.getline(city,len),cin.get(city,len)輸入。
*getline()是達到len長度時候結束,或者遇到換行的時候結束。但是get()遇到換行結束,但是可接受換行。
*
*/
using namespace std;
void main()
{
char city[20];
char name[20];
//cin.getline(city,20);cin.getline(name,20);與下一行等效
cin.get(city,20); cin.get(); cin.get(name, 20);
cout<< name<<"\t"<<city<< endl;
}
字符串:
#include<iostream>
#include<string>
/*
*字符串相當於字符數組,可以和字符數組一樣使用
*字符串可以直接賦值,相加,拼接,可以直接cin和cout
*/
using namespace std;
void main()
{
string str1 = "nihao";
if (str1[5] =='\0') { cout <<"hello everyone\n"; }
string str2 = str1 + " zxw\n";
cout<< str2<<str2.length()<<"\t"<<str2.size();
}
結構體和共用體的使用
結構體是可以定義多個數據類型,但是共用體是每次只能儲存一個值
#include<iostream>
#include<string>
/*
*/
using namespace std;
struct mystruct
{
string name;
int studentno;
char sex;
bool good : 1;
union id
{
float salary;
string career;
}x;
}my1;
void main()
{
my1.x.salary= 100;
}
枚舉:
只是定義了賦值操作,沒有運算操作,當然,賦值附很大的時候將會發出警告,按照原則,應該有多少賦值多少
#include<iostream>
#include<string>
/*
*/
using namespace std;
void main()
{
enum my{ONE=1,TWO=2,THREE};
cout<< THREE << endl;
}
指針:
在c++創建的時候,計算機分配用來儲存地址的內存,並不會去儲存值,所以為數據提供空間是一個獨立的步驟。指針的加減是以所在的類型為單位個數進行加減。*(a+1)=a[1];
創建動態數組:
#include<iostream>
#include<string>
/*
當內存耗盡時候new將會返回0,delete釋放內存,並不會刪除指針
*/
using namespace std;
void main()
{
int* p_int = new int;
*p_int= 1024;
delete p_int;
//delete p_int;不能再次調用釋放內存的delete,會發生我發預料的事情
float * P_float;
float ft = 2.1;
P_float= &ft;
//delete P_float;不能釋放棧里面的內存,只能釋放堆得
}
C++對數據有三種處理的方式自動存儲,隨着函數產生隨着函數消亡,靜態存儲,生命周期可能是整個程序的生命周期,動態存儲由程序員控制。
第三章 函數的使用
內聯函數:example:
inline void Swap(floata, float b)
{
a = a + b;
b = a - b;
a = a - b;
}
不能遞歸調用,原理是,所有的代碼翻譯成機器代碼進行解讀,正常的函數調用需要機器跳到指定的位置,但是內聯函數就不需要了,把代碼鑲嵌在內部,但是后果是占用的內存較多。
引用變量:
引用的變量建立就直接賦值;
傳遞參數的三種方式:值傳遞,指針傳遞和引用傳遞,引用實質上是內存中同一個地址的別名,對於引用,會發生值的改變,除非將值設置成const的引用的類型。小的值傳遞通常使用值傳遞,大一點的比如結構體這些使用指針,對象則使用引用傳遞,僅是建議。
默認參數從右往左開始賦值,這樣的方式僅僅是提供了一種便捷的操作方式而已。
void Swap(floata, float b=9)
{
a = a + b;
b = a - b;
a = a - b;
}
參數的數目和類型的不相同可以重載函數,建議少用。
template<classany> void Swap(any &q1,any &q2);//定義模板函數,在調用的時候叫做模板的實例化
template void Swap<int>(int &q1,int &q2);//模板顯示具體化
第四章 內存模型和名稱空間
一般可以分為三種文件:頭文件(負責各種聲明和全局變量或者define的定義等),結構文件(為頭文件的函數等定義的文件),調用文件(包含main的文件)
頭文件的包含一般使用“”,使用<>會從標准庫里面先去尋找。
儲存的持續性,作用域和鏈接性:
自動儲存持續性:在函數內部定義的局部變量(作用域是由一個花括號括起來的東西)
靜態存儲持續性:在函數外部定義或者static定義的變量,作用域由全局和局部。
動態存儲持續性:由程序員指定new創建直到delete刪除。存活周期結束。
注:在函數內部聲明的static 和new 創建的東西雖然存在,但是由於作用域的存在,在別的地方不好引用。
(在另一個源文件定義)在函數外部定義,則全局變量,鏈接性為外部,即所有文件可以使用,但是加上extern聲明存在之后可以使用。但是變量的定義的時候附加static 或者 const則在本文件可以使用,鏈接性為內部。
(在頭文件里面定義的變量,建議不要再這里面定義)包含頭文件,則包含里面的所有定義了,如果不聲明為內部鏈接性,在多個文件使用這個頭文件時候,將會發生重復定義錯誤。不能定義外部鏈接性的變量。
Example:(三個文件)
#pragma once
//mytemp1.h
#ifndef zylg1_
#define zylg1_
template<classany> void Swap(any &q1,any &q2);//定義模板函數,在調用的時候叫做模板的實例化
template void Swap<int>(int &q1,int &q2);//模板顯示具體化
const int b = 8;
static int a = 6;
#endif // !zylg1_
//metemp1.cpp
#include<iostream>
#include"mytemp1.h"
std::string extern1 = "具有外部鏈接性的變量,可以在全部文件使用,加上extern說明就行";
static std::string str1 ="聲明為靜態的具有內部鏈接性,只可以在本文件使用";
const std::string str2 ="聲明為靜態的具有內部鏈接性,只可以在本文件使用";
template<classany> void Swap(any &q1,any &q2)
{
q1 = q1 + q2;
q2 = q1 - q2;
q1 = q1 - q2;
}
//temp.cpp包含main()文件
#include<iostream>
#include"mytemp1.h"
#include<string>
using namespace std;
extern string extern1;//使用另外一個源文件定義的
void main()
{
extern1= "這是重新使用外部變量";
int a1 = 2, a2 = 4;
Swap(a1,a2);
cout<< a1 << a2 << endl;
cout<< extern1<<b<<endl;
}
(在另一個源文件)同樣的如果不添加static或者const的函數,則是外部鏈接性的。但是內部鏈接性聲明之后,那就意味着在別的源文件里面重新定義函數不會發生重復定義的錯誤。
//metemp1.cpp
#include<iostream>
void Swap(int &a,int &b)
{
a = a + b;
b = a - b;
a = a - b;
}
//temp.cpp包含main()文件
#include<iostream>
#include<string>
using namespace std;
extern void Swap(int &q1,int &q2);
void main()
{
int a1 = 2, a2 = 4;
Swap(a1,a2);
cout<< a1 << a2 << endl;
}
//metemp1.cpp
#include<iostream>
static void Swap(int &a,int &b)
{
a = a + b;
b = a - b;
a = a - b;
}
//temp.cpp包含main()文件
#include<iostream>
#include<string>
using namespace std;
void Swap(int &q1,int &q2)
{
q1 = q1 + q2;
q2 = q1 - q2;
q1 = q1 - q2;
}
void main()
{
int a1 = 2, a2 = 4;
Swap(a1,a2);
cout<< a1 << a2 << endl;
}
注:extern只是讓閱讀代碼的人知道外部存在這東西,並沒無多大作用,可省略,但不建議。這也就是頭文件的由來,可以看成是全部的外部的成員集合在一起,但是省略了extern。
由於c和c++編譯器處理的效果不一樣,
//temp.cpp包含main()文件
#include<iostream>
#include<string>
using namespace std;
extern "C++" void Swap(int &q1,int &q2);
void main()
{
int a1 = 2, a2 = 4;
Swap(a1,a2);
cout<< a1 << a2 << endl;
}
動態開辟:
C++的內存分成三個部分靜態變量,自動變量,和動態儲存部分,new負責在heap里面找到合適的內存。New的用法
//temp.cpp包含main()文件
#include<iostream>
#include<string>
using namespace std;
struct student
{
char name[20];
int num;
};
void main()
{
char ch1[30], ch2[30];
student *st1, *st2;
int *num1, *num2;
st1= new student;//place create in heap
st2= new (ch1) student;//place create in ch1
num1= new int;//place create in heap
num2= new (ch2) int;//create in ch2
cout<< st1 << "\t" << st2<< "\t" << &ch1 << endl;
cout<< num1 << "\t" << num2<< "\t" << &ch2 << endl;
}
命名空間:
//temp.cpp包含main()文件
#include<iostream>
#include<string>
/*
*不允許在函數內部命名名稱空間
*名稱空間可以嵌套
*當名稱空間的名稱省略的時候就相當於具有內部鏈接性的靜態全局變量。是一種好的替代方式。
*名稱空間的using聲明(使用單個)和using 編譯(使用全部)
*/
namespace myspace
{
using std::string;//using聲明
using std::cout;
using std::cin;
string name;
int num;
void show()
{
cout<< name << "\t" << num<<std::endl;
}
void input()
{
cin>> name >> num;
show();
}
}
namespace myspace//和上一個空間是同一個空間,未寫完繼續寫
{
string str = "你好啊,我在myspace空間里面";
namespace myspaceson //可以進行嵌套,命名空間就相當於一個作用域。
{
string str = "hello every one";
}
}
namespace my =myspace;//別名
void main()
{
using namespace myspace;//using 編譯
input();
cout<< myspaceson::str << std::endl;
}
命名空間的運用實例
#pragma once
//mytemp1.h
#ifndef zylg1_
#define zylg1_
namespacemyspace1
{
namespace//==static or constdefine
{
int number = 30;
}
void Swap(int &a,int &b);
}
namespacemyspace2
{
void Show(inta,int b);
}
#endif // !zylg1_
//metemp1.cpp
#include<iostream>
#include"mytemp1.h"
namespacemyspace1
{
void Swap(int &a,int &b)
{
a = a + b; b =a - b; a = a - b;
}
}
namespacemyspace2
{
using namespace std;
void Show(inta,int b)
{
cout<< "a=" << a << "\t b=" <<b << endl;
}
}
//temp.cpp包含main()文件
#include<iostream>
#include "mytemp1.h"
void main()
{
int a=2,b=4;
using namespace myspace1;//using 編譯
Swap(a,b);
myspace2::Show(a,b);
}
第五章 類的使用
#pragma once
//mytemp1.h
#ifndef zylg1_
#define zylg1_
namespacemyspace1
{
class Time
{
private:
int hours, minutes;
public:
Time(int,int);
Time();
void addMin(intm);
void addHor(inth);
void Reset();
Time operator+(const Time& t)const;
void Show()const;//對於不修改里面的值得函數,應該在后面加上const,防止數據修改
friend void display(constTime &t);
friend std::ostream&operator<<(std::ostream &os,const Time &t);
};
}
#endif // !zylg1_
//metemp1.cpp
#include<iostream>
#include"mytemp1.h"
namespacemyspace1
{
namespace
{
using std::cout;
using std::endl;
}
Time::Time()
{
}
Time::Time(inth=0,int m=0)
{
if (m >= 60)
{
hours= m / 60+h;
minutes= m % 60;
}
else
{
hours= h;
minutes= m;
}
}
void Time::addMin(int m)
{
hours+= (m + minutes) / 60;
minutes= (m + minutes) % 60;
}
void Time::addHor(int h)
{
hours+= h;
}
void Time::Reset()
{
hours= minutes = 0;
}
Time Time::operator+(constTime& t)const
{
return Time(hours + t.hours, minutes + t.minutes);
}
void Time::Show()const
{
cout<< hours << ":" << minutes<< endl;
}
void display(constTime &t)
{
cout<< t.hours << ":"<< t.minutes << endl;
}
std::ostream& operator<<(std::ostream & os, const Time &t)
{
cout<< t.hours << ":"<< t.minutes << endl;
return os;
}
}
//temp.cpp包含main()文件
#include<iostream>
#include "mytemp1.h"
/*
*規范的格式,在頭文件不許出現外部鏈接性的全局變量,在源文件盡量不出現,此外命名空間用起來,好了萬事大吉
*/
void main()
{
using myspace1::Time;
Time t1(1,31),t2(2,30),t3,t4;
t3= t1 + t2;
t1.Show();
t2.Show();
t3.Show();
t4= t1 + t2 + t3;//t1.operator+(t2.operator+(t3))
t4.Show();
display(t4);//it is friendfuntion
}
Cout<<返回的時ostream的對象,所以可以繼續<<
第六章 類和動態內存分配
:(類的聲明只是描述內存的分配,但是不會分配內存)
類中的靜態成員不能夠直接初始化,其余可以,但是const int/枚舉 類型的靜態成員可以初始化。靜態成員賦值那就意味該靜態變在內存中存在,那就得分配內存(類的聲明只是描述內存的分配),所以如例題中:在類中定義staticc int num_strings ;
然后初始化 int StringBad::num_strings = 3;這就相當於申請了一個int大小的內存去儲存靜態變量。
class StringBad
{
private:
char * str="shixsa";//可以賦值,但是意義不大。
int len=3;
public:
//static const std::stringnum_strings="hello";//can`t not to initialize
static const int num_strings = 2;//can initialize
public:
StringBad(const char *s);
StringBad();
~StringBad();
friend std::ostream &operator<<(std::ostream &os,const StringBad &st);
}
靜態變量的使用
#pragma once
//mytemp1.h
#ifndef zylg1_
#define zylg1_
namespace myspace
{
namespace
{
using std::cout;
using std::cin;
using std::endl;
}
class StringBad
{
private:
char * str="shixsa";
int len=3;
public:
static int num_strings;
void display();
StringBad(const char *s);
StringBad();
//~StringBad();
friend std::ostream &operator<<(std::ostream &os,const StringBad &st);
};
}
#endif // !zylg1_
//metemp1.cpp
#include<iostream>
#include"mytemp1.h"
namespace myspace
{
int StringBad::num_strings = 3;
void StringBad::display()
{
cout<< StringBad::num_strings << endl;
}
StringBad::StringBad()
{
StringBad::num_strings++;
}
}
//temp.cpp包含main()文件
#include<iostream>
#include"mytemp1.h"
void main()
{
using myspace::StringBad;
StringBad st;
st.display();
StringBad st1;
st1.display();
StringBad st2;
st2.display();
StringBad st3;
st3.display();
}
構造1,構造2,析構2,析構2
1) 默認構造函數 classname::classname(){}
2) 復制構造函數 classname::classname(const classname& cla){}
StringBad st;
StringBad st1(st);
StringBad st2=StringBad(st);
StringBad st3=st;
StringBad* st4 = new StringBad(st);
在賦值進行操作時,出現指針或者其他因素時最好顯示定義,不然兩個指針指向同一地址,一旦釋放,就不好了
3) 賦值操作符=
4) 默認析構函數classname::~classname()
5) 地址操作符&
new創建的用delete,但是new []創建的用delete []
//zylgstring.h
#pragma once
#include<iostream>
#ifndefZYLG_STRING
#define ZYLG_STRING
usingstd::cin;
usingstd::cout;
using std::ostream;
using std::istream;
namespaceZYLGSPACE
{
class String
{
private:
char *str;
int len;
static int num_strings;
static const int CINLIMIT = 100;
public:
//constrators and other methods
String(const String &s);//復制構造函數
String();
String(const char *s);
~String();//析構函數
int length()const {return len; }
//overloaded operator methods,()=[]->這四個符號只能在類的成員函數里面進行重載
String & operator=(const String& s);
String & operator=(const char*s);
char & operator[](int i);
const char & operator[](inti)const;
//friend function
friend bool operator>(constString& s1, const String &s2);
friend bool operator<(constString& s1, const String &s2);
friend bool operator==(constString& s1, const String &s2);
friend std::ostream &operator<<(std::ostream &os, const String &s);
friend std::istream &operator>>(std::istream &is, String &s);
//static function
static int HowMany();
};
}
#endif // !ZYLG_STRING
//zylgstring.cpp
#include<cstring>
#include"zylgstring.h"
#pragma warning(disable:4996)
namespaceZYLGSPACE
{
int String::num_strings = 0;
int String::HowMany()
{
return num_strings;
}
String::String(constchar* s)
{
len= std:: strlen(s);
str= new char[len + 1];
//std::strcpy(str, s);
num_strings++;
}
String::String()
{
len= 4;
str= new char[1];
str[0]= '\0';
num_strings++;
}
String::String(constString& s)
{
num_strings++;
len= s.len;
str= new char[len + 1];
//std::strcpy(str, s.str);
}
String::~String()
{
--num_strings;
delete[] str;
}
String & String::operator=(constString& st)
{
if (this == &st) {return *this; }
delete[] str;
len= st.len;
str= new char(len + 1);
//std::strcpy(str, st.str);
return *this;
}
String & String::operator=(constchar* s)
{
delete[] str;
len= std::strlen(s);
str= new char(len + 1);
std::strcpy(str,s);
return *this;
}
char & String::operator[](inti)
{
return str[i];
}
const char & String::operator[](inti)const
{
return str[i];
}
bool operator<(const String& s1,constString& s2)
{
return (std::strcmp(s1.str,s2.str)<0);
}
bool operator==(const String& s1, constString& s2)
{
return (std::strcmp(s1.str,s2.str)==0);
}
bool operator>(const String& s1, constString& s2)
{
return s2.str < s1.str;
}
ostream & operator<<(ostream & os, const String&st)
{
os << st.str;
return os;
}
istream & operator >> (std::istream & is, String &s)
{
char temp[String::CINLIMIT];
is.get(temp, String::CINLIMIT);
if (is)
{
s = temp;
}
while (is &&is.get() != '\n')
{
continue;
}
return is;
}
}
第七章 類的繼承
默認參數構成的構造函數,在全部是默認參數時,直接定義對象就行,不用加括號,如下
tabletennisplayer(const char * first="none",constchar * last="none",bool has=false);//exist default
tabletennisplayer::tabletennisplayer(constchar * first, const char * last ,bool has ){}
tabletennisplayer t1("buxnasox"),t2;
成員初始化列表只能用於構造函數,而且:之后的數只能是構造函數或者成員變量,調用時先調用基類的構造函數再調用子類的構造函數。析構函數則是先子類再基類。
2.論繼承:繼承有公有,私有和保護繼承,保護繼承是子類能訪問,但是其他類不能訪問,在基類的成員變量和成員函數如果私有的,那就得通過基類的公有或者保護函數來訪問。
子類可以在基類的基礎上添加屬性,但是不能刪除屬性。
構造函數,析構函數,友元函數不能繼承,當然賦值=也不能繼承
3.虛函數的理解:虛函數的存在可以使用動態連編(在運行時選擇正確的虛方法的代碼),虛函數的實現的方式是,在類中存在虛方法時,類就會自動增加一個一種數組(虛函數表)vtal,里面存放了類對象聲明的虛函數的地址。那就形成了每一個函調用時都額外增加了到該表中尋找地址的操作。當然虛函數,也只有成員函數和析構函數可以成為。
Class A;
Class B:publicA
A *a,a1;
B b;
a=&a1;a->display();
a=&b;a->display();
在基類聲明display()為虛函數
虛基類是 “虛函數=0;”
第八章 重用代碼
多重繼承:
多重繼承最好有虛基類,排除二義性,再者就是,進行子類構造的時候,並不能進行虛基類的構造,因為數據不能從子類傳遞到虛基類的基類。如果一個派生類有多個派生基類,而多個派生基類又有共同基類,則會在該派生類里面保存共同基類的數據成員的多份同名成員。在引用這些同名成員的時候必須加上直接基類的限定符。
class A
{
public:
int n;
void fun();
};
class B :public A
{
public:
int data_b;
};
class C :public A
{
public:
int data_c;
};
class D :public B,public C
{
public:
int data_d;
};
D d1;
d1.B::fun();//正確的使用成員數據的方式
d1.C::fun();
注意:子類只能直接調用直接基類的東西
但是使用虛擬繼承,那樣只會在D類里面只有一個間接基類的成員,但是由於構造函數不能從子類傳遞數據到虛擬繼承的派生類,所以構造函數必須全部重新構造完全
//temp.cpp包含main()文件
#include<iostream>
#include"work.h"
class A
{
public:
A(int n):n(n){}
int n;
void fun();
};
class B :virtual public A
{
public:
B(int n) :A(n) {}
int data_b;
};
class C :virtual public A
{
public:
C(int n) :A(n) {}
int data_c;
};
class D :public B,public C
{
public:
D(int n) :A(n), B(n), C(n) {}//如果不是虛擬繼承將會發生錯誤
int data_d;
};
void main()
{
//using namespacezylgclassextend;
using namespace WORKSPACE;
D d1(1);
d1.fun();
}
//stack.h
#pragma once
#ifndefSTACK_H_
#define STACK_H_
namespaceSTACKSPACE
{
template <classType>
class Stack
{
private:
enum { MAX = 10 };
int top;
Type items[MAX];
public:
Stack();
bool isfull()const;
bool isempty()const;
bool push(constType& item);
bool pop(Type &item);
};
template <classType>
Stack<Type>::Stack():top(0) {}
template <classType>
bool Stack<Type>::isempty()const {return top == 0; }
template <classType>
bool Stack <Type>::isfull()const {return (top+1) == MAX; };
template <classType>
bool Stack<Type>::push(constType& item)
{
if (top < MAX)
{
items[top++]= item;
return true;
}
else return false;
}
template <classType>
bool Stack<Type>::pop(Type&item)
{
if (top > 0)
{
item = items[--top];
return true;
}
else
{
return false;
}
}
}
#endif // !STACK_H_
template <class T,int n>
classclassname
{
public:
voidshow();
};
template <class T,int n>
void classname<T, n>::show() {}
template <classT1,class T2>
class classname
{
public:
void show();
};
template<class T1,class T2>
void classname<T1, T2>::show() {}
可以在模板里面加入模板,也可以模板函數,當然有內部類的說法,可以定義內部類,類定義得簡單一些就使用內部類吧。
內部類
內部類與外部類的關系
內部類和外部類是什么關系了,事實上他們什么關系也不是,既不是朋友,也不是父子關系,外部類對內部類沒有特權, 內部類對外部類也沒有特權, 他們的關系,跟內部類定義在外部類外面一樣。
內部類的使用方法
如果要在調用內部類函數,可以主要使用:
[cpp] view plain copy
1. A::InClass a;
2. a.funcB();
內部類的作用
1)內部類主要是為了避免命名沖突;(內部類定義為public)
2)為了隱藏名稱(內部類定義為private/protected)
class A
{
class B
{
public:
void display() {std::cout<< "你好\n"; }
};
B b1;
public:
void show() {b1.display(); std::cout<< "hello\n"; }
};
內部模板的使用
template <classT1,class T2>
class classname
{
public:
template<classU>
class innerclass//內部模板
{
U u1;
public:
void display(Uu1, T1 t);
};
innerclass<int> in1;
template<classY>//模板函數
void prin(Ystr);
void show();
};
template <classT1,class T2>
void classname<T1, T2>::show() {}
template<classT1,class T2>
template<classU>
void classname<T1, T2>::innerclass<U>::display(Uu1,T1 t) { cout << u1 + t << endl; }
template <classT1,class T2>
template <classY>
void classname<T1, T2>::prin(Y str) { cout <<str << endl; }
使用template主要是讓T1等有定義出來,其余就和內部類一樣。模板就和正常的數據一樣,那自然也可以 template<template<classTT> class th, class T1,class T2> class th2 {};
當然友元函數也可以friend void show(T1,T2);//類里面聲明
template <classT1,class T2>//類外定義
void show(T1t1, T2 t2) { cout << t1 + t2 << endl; }
template<class T>起到傳遞類型的作用
第九章 友元異常和其他
友元類:
當定義為友元類時候,友元類可以訪問此類的私有成員,定義友元類不用說明其存在
class A
{
public:
friend class B;
};
class B
{
};
但是竟可能不要定義友元類,可以通過友元函數去處理問題。
異常:
Abort()和exit()的區別是,exit()會刷新文件緩沖區,但是不會回顯消息。
Void fun()throw(數據類型);
Try
{
fun();
}
Catch(數據類型 e)
{
//處理程序
}
異常處理的原理是,首先會讓異常的地方throw,然后try{}塊結束釋放內存,當然throw的數據是異常數據的重新的備份,它在發現異常的時候,將拋出的數據進行了復制,然后拋出這個數據。Catch塊對應數據類型捕捉異常,之后進行異常的處理。這就是堆棧飢解退。
一般的函數調用是這樣的,比如a調用b,那b函數就會在堆棧的頂端,同時頂端的棧堆將會為從a傳遞進來的參數和b自己創建的變量以及返回地址分配內存。如果b再調用c也是如此,在b調用完成的時候,堆棧將會釋放內存,根據返回地址找到a的位置,繼續執行下面的語句。
異常處理的基類應該放在最后一個catch里面,因為放在前面將會捕捉派生的對象。
如果不知道catch的對象類型,可以使用…代替
RTTI(運行階段類型識別)只是適用於包含虛函數的類,因為也只有虛函數才去區分誰是誰
dynamic_cast安全轉換對象
tabletennisplayer* t1=newtabletennisplayer();
rateplayer *r1 = new rateplayer("hello","hello",false,2);
t1 = dynamic_cast<tabletennisplayer *>(r1);//安全轉換,失敗返回空指針
t1->name();
ciwai
const_cast()把const對象類型的數據變成普通的,地址一樣,然后可以進行修改
staic_cast/reinterpre_cast
typeid()可以知道對象的所屬類型
if (typeid(rateplayer)== typeid(*t1)) { cout<< "\nthey are same\n"; cout<< typeid(*t1).name()<< endl << typeid(*t1).hash_code() << endl; }
第十章 string類和標准模板庫
string類:
不解釋
智能指針:
Auto_ptr必須顯示的構造,還有就是智能是定義單個變量不能使數組,因為delete而不是delete[],會有讓權操作,也就是第一個指針的內容賦值給下一個時,第一個失效。注意:智能指針是自動調用delete,也就是堆棧里面的元素,所以不能把自變量的地址賦給智能指針。
auto_ptr<int> i1(newint);//必須顯示的構造,而且不能使數組,因為數組使用delete[]來釋放內存。
i1= auto_ptr<int>(ptr);
cout<< *i1 << endl;*
STL:
序列式容器vector有超尾指針end,有begin,size(),pop_back(),push_back(),erase(),insert()
vector<int>::iterator int_iterator;
i1.push_back(3);//在vectror后面添加元素
i1.push_back(2);
i1.push_back(1);
i1.pop_back();
int_iterator= i1.begin();
cout<<"元素的數量:"<< i1.size()<<"\n"<< "現在可以容納的數量:"<<i1.capacity()<< endl;
cout<< "vector :\n";
while (int_iterator !=i1.end())
{
cout<< *int_iterator << endl;
int_iterator++;
}
cout<< *(--int_iterator) << endl;
i1.erase(i1.begin(),i1.begin() + 2);//erase清除前面兩個元素
cout<< "erase result:\n";
int_iterator= i1.begin();
while (int_iterator !=i1.end())
{
cout<< *int_iterator << endl;
int_iterator++;
}
vector<int> int_temp = {1,3,2,4,5 };
cout<< "have insert :\n";
i1.insert(i1.begin(),int_temp.begin(),int_temp.end());//insert()插入元素
for (int_iterator =i1.begin(); int_iterator != i1.end(); int_iterator++) { cout<< *int_iterator << endl; }
當然可以接受stl的算法,比如for_each(),random_shuffle(),sort()
cout << "for_each():\n";
std::for_each(int_temp.begin(),int_temp.end(), display);//循環傳遞元素給作為函數參數
cout<< "random_shuffle();\n";
std::random_shuffle(int_temp.begin(),int_temp.end());//打亂順序
std::for_each(int_temp.begin(),int_temp.end(), display);
cout<< "sort()\n";
std::sort(int_temp.begin(),int_temp.end());
std::for_each(int_temp.begin(),int_temp.end(), display);
std::random_shuffle(int_temp.begin(),int_temp.end());
cout<< "重新排序\n";
std::sort(int_temp.begin(),int_temp.end(), compa);//進行排序
std::for_each(int_temp.begin(),int_temp.end(), display);
voiddisplay(inta) { cout << a << endl; }
bool compa(int &a,int &b) { return a > b ?true : false; }
sort里面既然接受地址那樣,那下面也成立
cout << "對數組進行的操作\n";
int arra[5] = {1,9,0,1,3 };//stl算法對數組進行操作
std::sort(arra,arra + 5,compa);
迭代器(廣義上來講是一種指針):
輸入,輸出,正向,雙向,隨機迭代器
Copy()傳達的時賦值的操作
std::ostream_iterator<int,char> out(cout,"\n");
std::copy(arra,arra + 5, int_temp.begin());
std::copy(int_temp.begin(),int_temp.end(), out);
cout << "元素反置\n";
std::copy(int_temp.rbegin(),int_temp.rend(), out);
cout<< "向后插入元素\n";
copy(arra,arra + 3, std::back_insert_iterator<vector<int>>(int_temp));
copy(int_temp.begin(),int_temp.end(), out);
cout<< "向前抽入元素" << endl;
copy(arra,arra + 3, std::insert_iterator<vector<int>>(int_temp,int_temp.begin()));
copy(int_temp.begin(),int_temp.end(), out);
聯合容器:
Set和muitimap等,set的操作set_union(),set_intersection(),set_diffrence()
std::set<int> A(arra,arra+5);//set
cout<< "A is\n";
std::copy(A.begin(),A.end(), out);
std::set<int>B;
B.insert(9);
B.insert(2);
cout<< "B is \n";
std::copy(B.begin(),B.end(), out);
std::set<int>C;
cout<< "set_union()\n";
std::set_union(A.begin(),A.end(), B.begin(), B.end(), std::insert_iterator<std::set<int>>(C, C.begin()));
//std::copy(C.begin(), C.end(), out);
std::set_union(A.begin(),A.end(), B.begin(), B.end(), out);
typedef std::pair<int, std::string>Pair;
std::multimap<int, std::string>mapcode;
mapcode.insert(Pair(1, "hello"));
mapcode.insert(Pair(2, "everyone"));
*out++= mapcode.size();
cout<< endl;
std::pair<std::multimap<int, std::string>::iterator, std::multimap<int, std::string>::iterator> range;
range=mapcode.equal_range(1);
for (std::multimap<int, std::string>::iterator it = range.first;it!= range.second; ++it) { cout<< (*it).second << endl; }
第十一章 輸入輸出和文件
輸入流和輸出流:ios_base->ios->各種流
緩沖區為了更有效率的輸出數據,先把數據囤積起來一起輸出
輸出的函數有<<,put(單個字符),write(數組的起始地址,數組的位置)
Flush強制刷新緩沖區
另外有格式控制的頭文件,width(10),fill(‘#’),setf(ios_base::xxx)
流的狀態(eodbit,badbit,failbie,goodbit,eof(),bad(),fail(),rdstate(),clear(),setstate())
文件的操作
注:默認情況下以ios_base::trunc清除文件所有的內容打開文件,這樣這個就不能和in連用
基本:ios_base::in/out/ate 讀文件/寫入文件/在末尾寫文件
追加:ios_base::app/trunc
此外可以二進制的形式打開文件
為了寫入和讀出的方便,用二進制的方式寫入和讀出來,但是對於有虛函數的對象不適用
自由存儲:seekg、seekp()其中的參數有正整數向右移動,負整數向后移動,ios_base::beg/end/cur,檢查文件指針的位置tellg/tellp()
//temp.cpp包含main()文件
#include<iostream>
#include<fstream>
void main()
{
const char* file = "cxq.txt";
std::ifstream fin(file);
char ch;
if (fin.is_open())
{
while (fin.get(ch))
{
std::cout<< ch;
}
}
fin.close();
std::ofstream fout(file);
if (!fout.is_open()) {std::cerr<< "Can`t open"<< file << " file for output.\n"; exit(EXIT_FAILURE); }
char str[] = "我是專業路過\n";
fout<< str << std::endl;
fout.close();
fin.clear();//清空輸入流
fin.open(file);
while (fin.get(ch))
{
std::cout<< ch;
}
fin.close();
}
//temp.cpp包含main()文件
#include<iostream>
#include<fstream>
struct student
{
int num;
char name[20];
float score;
};
void main()
{
student st1{1500730142,"zylg",99.9};
student st2{ 1500730141,"zzz",1.1 };
char *file = "student.dat";
std::fstream fin;
int place = (sizeof st2);
fin.open(file,std::ios_base::out|std::ios_base::in|std::ios_base::app|std::ios_base::binary);
fin.write((char *)&st2, sizeof st2);
fin.seekg(-place,std::ios_base::end); //訪問的位置是最后一個結構體的位置
while (fin.read((char*)&st2,sizeof st1))
{
std::cout<< st2.num << st2.name << st2.score << std::endl;
}
fin.close();
}