目
錄
<a target="_blank" href="#_toc395195908">1 開始學習c++.............................................................................................................. 4</a>
<a target="_blank" href="#_toc395195909">1.1 c++的頭檔案....................................................................................................... 4</a>
<a target="_blank" href="#_toc395195910">1.2 命名空間............................................................................................................... 4</a>
<a target="_blank" href="#_toc395195911">1.3 更嚴格的類型轉化................................................................................................ 4</a>
<a target="_blank" href="#_toc395195912">1.4 new和delete....................................................................................................... 4</a>
<a target="_blank" href="#_toc395195913">1.5 内聯函數............................................................................................................... 4</a>
<a target="_blank" href="#_toc395195914">1.6 引用...................................................................................................................... 5</a>
<a target="_blank" href="#_toc395195915">1.7 函數的重載........................................................................................................... 5</a>
<a target="_blank" href="#_toc395195916">2 類和對象...................................................................................................................... 6</a>
<a target="_blank" href="#_toc395195917">2.1 c++類成員 的保護.............................................................................................. 6</a>
<a target="_blank" href="#_toc395195918">2.2 c++類的本質....................................................................................................... 6</a>
<a target="_blank" href="#_toc395195919">2.3 類的作用域........................................................................................................... 6</a>
<a target="_blank" href="#_toc395195920">2.4 類的構造和析構函數............................................................................................ 6</a>
<a target="_blank" href="#_toc395195921">2.5 構造函數的初始化成員清單................................................................................. 6</a>
<a target="_blank" href="#_toc395195922">2.5.1 原則:........................................................................................................... 7</a>
<a target="_blank" href="#_toc395195923">2.6 拷貝構造函數....................................................................................................... 7</a>
<a target="_blank" href="#_toc395195924">2.6.1 淺拷貝........................................................................................................... 7</a>
<a target="_blank" href="#_toc395195925">2.6.2 深拷貝........................................................................................................... 7</a>
<a target="_blank" href="#_toc395195926">2.6.3 原則:........................................................................................................... 8</a>
<a target="_blank" href="#_toc395195927">2.7 常量類成員,常量對象。..................................................................................... 8</a>
<a target="_blank" href="#_toc395195928">2.8 explicit................................................................................................................. 8</a>
<a target="_blank" href="#_toc395195929">2.9 this指針............................................................................................................... 8</a>
<a target="_blank" href="#_toc395195930">2.10 類的static成員變量............................................................................................ 8</a>
傳統的c頭檔案。(支援.h頭檔案,比如:#include<stdio.h>)
c++頭檔案。(不加.h的頭檔案,比如:#include<iostream>)
hpp檔案件。(支援.hpp頭檔案)
在工作中如果有c的也有c++的,最好使用帶有.h的頭檔案
cout << "hello world!"<< endl;
這裡的”<<”實際上進行了操作符的重載。
a:使用類似:using
namespace std;
b:如果不使用用usingnamespace
std;那麼這個時候可以在代碼中使用類似下面的情況:
std:cout << "helloworld\n" << endl;
c++引入了新的概念,命名空間可以有效避免大型項目中的各種名稱沖突
class關鍵字
class是c++的核心,是面向對象程式設計的核心内容。一個class案例:
#include <iostream>
#include <string.h>
using namespace std;
class man{
public://共有的
char name[100];
private://私有的,隻要下面不通路這裡的age,程式就不會出現問題
int age;
public:
int sex;
}; //注意:這裡最後要有一個分号
int main()
{
man m;
strcpy(m.name,"tom");
m.sex = 1;
cout << m.name << m.sex << endl;
return 0;
}
自定義命名空間:
使用匿名命名空間:
namespace
void
func()
{
cout
<< "demo2
func" <<
endl2;
}
通過volatile關鍵字使代碼不被編譯器優化,案例:
volatile int i=0;//保證i不被編譯器優化,以便能進行中間步驟
i+=6;
i+=7;
如果加了volatile關鍵字,那麼就使程式不被優化成為
i+=13
在c++,不同類型的指針是不能直接指派的,必須強轉。(也就是如果兩個指針類型不同,不能直接把一個指派給另外一個,而是要通過強轉的方式實作)
c++中不建議使用malloc和free開辟記憶體或釋放記憶體。而是使用new和delete。
new和delete是c++内建的操作符,不需要有任何頭檔案,用new配置設定的記憶體必須用delete釋放,不要用free。
int *p=new int;
等價于:int*p=new int(10);//配置設定記憶體的同時初始化
*p =10;
delete p;
p = null;
new建立數組的方法new[];
int *p=new int[10];
//表示開辟10個空間的數組
for(int i=0;i<10;i++)
p[i]=i;
//輸出結果
for(int i = 0;i<10;i++)
cout << p[i] << endl;
delete []p; //如果要删除這些數組的空間,要加上[],表示這時候删除的是一個數組。
inline關鍵字的意思是,内聯函數不作為函數調用,而是直接把内聯函數的代碼嵌
入到調用的語句中
内聯函數适合函數代碼很少,并且有頻繁的大量調用。
引用就是一個變量的别名,比如
int a = 5;
int &c = a;
//這裡的c就相當于是a的别名
引用不是位址,雖然加上了&。
函數的預設參數
c++允許函數在定義的時候,提供預設參數,如果調用函數的時候沒有提供形參,那麼形參的值就是預設值,也就是說用預設值。
#include
<iostream>
<stdio.h>
<stdlib.h>
<string.h>
using
std;
func(int
a
=
10)
printf("a
%d",a);
int
main()
func();
//這時候沒有填寫參數
return
0;
上面代碼運作的結果是10.
此外,函數會自動通過傳遞的參數類比對調用哪個函數,案例如下:
引用做為函數的參數,沒有出棧,入棧的操作,是以效率更高
如果要使引用參數的值不能在函數内部被修改,那麼就定義為常量引用 const &
引用例子:
函數的名稱是一樣的,但參數不同可以重載
函數參數相同,但傳回值不同,不可以重載
a:模闆的概念
我們已經學過重載(overloading),對重載函數而言,c++的檢查機制能通過函數參數的不同及所屬類的不同。正确的調用重載函數。例如,為求兩個數的最大值,我們定義max()函數需要對不同的資料類型分别定義不同重載(overload)版本。
//函數1.
int max(int x,int y);
{return(x>y)?x:y ;}
//函數2.
float max( float x,float y){
return (x>y)? x:y ;}
//函數3.
double max(double x,double y)
{return (c>y)? x:y ;}
但如果在主函數中,我們分别定義了 chara,b;
那麼在執行max(a,b);時
程式就會出錯,因為我們沒有定義char類型的重載版本。
現在,我們再重新審視上述的max()函數,它們都具有同樣的功能,即求兩個數的最大值,能否隻寫一套代碼解決這個問題呢?這樣就會避免因重載函數定義不
全面而帶來的調用錯誤。為解決上述問題c++引入模闆機制,模闆定義:模闆就是實作代碼重用機制的一種工具,它可以實作類型參數化,即把類型定義為參數,
進而實作了真正的代碼可重用性。模版可以分為兩類,一個是函數模版,另外一個是類模版。
b:函數模闆的寫法
函數模闆的一般形式如下:
template <class或者也可以用typename
t>
傳回類型
函數名(形參表)
{//函數定義體
說明: template是一個聲明模闆的關鍵字,表示聲明一個模闆關鍵字class不能省略,如果類型形參多餘一個
,每個形參前都要加class <類型
形參表>可以包含基本資料類型可以包含類類型.
請看以下程式:
//test.cpp
using std::cout;
using std::endl;
//聲明一個函數模版,用來比較輸入的兩個相同資料類型的參數的大小,class也可以被typename代替,
//t可以被任何字母或者數字代替。
template <class
t min(t x,t y)
return(x<y)?x:y;}
void main( )
intn1=2,n2=10;
doubled1=1.5,d2=5.6;
cout<<
"較小整數:"<<min(n1,n2)<<endl;
"較小實數:"<<min(d1,d2)<<endl;
system("pause");
程式運作結果:
程式分析:main()函數中定義了兩個整型變量n1
, n2 兩個雙精度類型變量d1 , d2然後調用min(
n1,n2); 即執行個體化函數模闆t min(tx, t y)其中T為int型,求出n1,n2中的最小值.同理調用min(d1,d2)時,求出d1,d2中的最小值.
c:類模闆的寫法
定義一個類模闆:
template < class或者也可以用typename
t >
class類名{
//類定義......
};
說明:其中,template是聲明各模闆的關鍵字,表示聲明一個模闆,模闆參數可以是一個,也可以是多個。
例如:定義一個類模闆:
// classtemplate.h
#ifndef classtemplate_hh
#define classtemplate_hh
template<typename
t1,typename t2>
class myclass{
private:
t1 i;
t2 j;
myclass(t1 a, t2 b);//constructor
void show();
};
//這是構造函數
//注意這些格式
template <typename
myclass<t1,t2>::myclass(t1 a,t2 b):i(a),j(b){}
//這是voidshow();
void myclass<t1,t2>::show()
cout<<"i="<<i<<",j="<<j<<endl;
#endif
// test.cpp
"classtemplate.h"
void main()
myclass<int,int>class1(3,5);
class1.show();
myclass<int,char>class2(3,'a');
class2.show();
myclass<double,int>class3(2.9,10);
class3.show();
最後結果顯示:
如果類函數傳回的是成員變量的指針,為了避免在類外部成員變量被修改,是以函數就要傳回常量指針
class
man{
char
name[100];
age;
public:
//共有方法
set_name(const
*s)
memset(name,0,sizeof(name));
if(strcmp(s,"tom")
==
0)
return;
strcpy(name,s);
set_age(int
i)
age
i;
*get_name()
return
name;
get_age()
man
m;
m.set_name("marry");
//如果非想name改成tom,可以使用下面的方式
*p
m.get_name();
strcpy(p,"tom");
<< m.get_name()
<< endl;
如果一個類成員變量和一個全局變量重名,那麼在類成員函數當中預設通路的是類的成員變量.
在類的内部通路全局辨別,使用關鍵字::,表示釋放全局變量或者全局函數
類其實就是結構的資料成員加可執行代碼,統一提供封裝,繼承,多态。
在類内部,沒有權限限定符,預設是private
在結構内部,沒有權限限定符,預設是public
一個類的案例:
編寫頭檔案:
#ifndef
test_h
#define
man();
*s);
i);
const
*get_name();
get_age();
//
//很有可能被編譯器編譯為inline了
//
//
編寫頭檔案的實作代碼如下:
"test.h"
man::man()
{}
man::set_name(const
man::set_age(int
*man::get_name()
man::get_age()
類的調用的簡單案例:
m.set_age(20);
//類的大小實際上是成員變量的大小,和去掉方法後的結構體的大小時相同的
printf("sizeof(man)
%d\n",sizeof(man));
<< m.get_age()
類成成員變量作用域局限于類内部,類的外部是不可見。
一般不要在頭檔案裡面定義變量。否則會出現問題。
構造函數名稱和類的名稱一緻,而且沒有傳回值,在一個類執行個體化為一個對象的時候,自動調用。
如果沒有寫構造函數,會生成一個預設的構造函數和析構函數,這時候編譯器會自動生成。
一個對象在銷毀的時候會自動調用析構函數。
如果想傳遞給函數一個類的變量,為了記憶體消耗減小,傳遞的是一個類的指針。或引用
初始化成員清單隻能在構造函數使用
const成員必須用初始化成員清單指派
引用資料成員必須用初始化成員清單指派
案例:
age;
//如果是一個常量,必須是通過初始化常量清單的方式指派,也就是說通過:方式指派
//如果這裡寫上man和~man,這時候會出現錯誤。
man();//構造函數的作用是初始化參數值
//重載構造函數
man(const
*);
*s,int
~man();
test();
編寫實作的代碼:
//構造函數,在對象被執行個體化的時候調用
man::man():age(24)
//通過後面加上:的方式初始化成員變量的值
<< "man"
//初始化name的值
//構造函數的重載
man::man(const
*s):age(14)
//之是以在後面初始化值,是因為類的成員變量加了const了。
*s,
i):age(15)
<< "man(const
char *s,
int i)
diao yong
le" <<
endl;
//動态配置設定記憶體,也是通過new的方式實作
//通過這種方式給成員變量指派
man::~man()
//要想清楚在構造函數裡配置設定的記憶體,需要在這裡釋放記憶體
//由于構造函數裡隻有一個,是以在不同的構造函數裡面給函數成員指針配置設定記憶體的時候,一定
//要統一new或者new
<< "~man"
//age
man::test()
m;
//在棧當中将man這個類執行個體化為一個對象叫man
m.set_name("toto");
//cout
<<
"----重載構造函數後的參數(1個參數)----"
<< "--one
argumemts--"
//有參構造的調用
m2("hello");
m.set_name("toto2");
<< m2.get_age()
<< m2.get_name()
"----重載構造函數後的參數(2個參數)----"
<< "----two
arguments----"
m3("hello",20);
m3.set_name("toto3");
<< m3.get_age()
<< m3.get_name()
編寫main函數:
m.test();
//調用沒有參數的構造函數,在堆執行個體化一個對象
new
//要寫下面一句,避免出現記憶體洩露!!
delete
p;
//不能通過free(*p2)的方式使用
p
null;
*p2
man("hello",100);
p2;
p2
由于析構函數隻有一個,是以在不同的構造函數裡面給函數的成員指針配置設定記憶體的時候,一定要統一new或者new[]
兩個對象之間成員變量簡單的指派。
比如:
man m1;
man m2 = m1;
不同的對象指針成員指向不同的記憶體位址,拷貝構造的時候不是簡單的指針指派,而是将記憶體拷貝過來(先申請記憶體空間)。
如果類成員有指針,那麼需要自己實作拷貝構造函數,不然存在淺拷貝的風險。
類成員後面跟關鍵字const意思是告訴編譯器,這個函數内部不會對類成員變量做任何修改。
函數的參數如果是一個類,那麼就用類的引用。如果不想參數被調用函數内部修改,那麼就采用const&
demo
demo()
<< "demo"
demo(int
<< "demo
int" <<
i <<
~demo()
<< "~demo"
//定義對象數組,同時調用帶有參數的構造函數
d[3]
{demo(1),demo(2),demo(3)};
<< "hello
world!"
告訴c++編譯器,要明确的調用這個構造函數,而不要自作聰明的認為=操作符是要調用構造的。
頭檔案:
man_h
*name;
static
count;//定義一個類的靜态成員變量,不可以進行初始化
explicit
man(int
age);//加了explicit之後表示就用這個構造函數。
&it);
int i
= 0);
const;
*get_this();
set_count(int
get_count();
實作類:
"man.h"
man::count
0;//類靜态成員變量初始化的方式
man::man():age(0),
name(null)
man::man(int
age)
<< "man
this->age
&it)
<< "copy
man" <<
name
char[100];
strcpy(name,
it.name);
it.age;
//man::man(const
//{
s);
//}
//man::man(int
age
<< s
<< i
[]name;
*man::get_this()
this;
man::set_count(int
count
10;//類的靜态函數内部不能直接通路類的動态成員變量。
man::get_count()
count;
main的代碼
test01()
m1("tom",
100);
m2
m1;//在棧當中将man這個類執行個體化為一個對象叫m
<< "m2.name:"
m1.set_name("hello");
test02(const
&m)
//man::count
200;
man::set_count(200);
printf("m
%p\n",
&m);
printf("%p\n",
m.get_this());
//m.set_count(500);
m1;
<< m1.get_count()
"m1"
m1.get_name()
man("hello",
100);//調用沒有參數的構造函數,在堆執行個體化一個對象
p;
this就是指向自己執行個體的指針
字元串操作的案例:
mystring_h
//一個單例的能夠動态配置設定記憶體的字元串
mystring
*self;
*s;
*makestring(const
*s
= null);
deletestring();
~mystring();
*get_s()
set_s(const
protected:
mystring();
mystring(const
頭檔案的實作代碼:
"mystring.h"
*mystring::self
*mystring::makestring(const
if
(self
null)
(s
self
mystring;
else
self
mystring(s);
self;
mystring::deletestring()
!=
null;//釋放指針之後,指派null,這樣就可以再次建立類的執行個體
mystring::mystring():
s(null)
mystring::mystring(const
len
strlen(s);
this->s
char[len
+
1];
strcpy(this->s,
this->s[len]
&it)//通過拷貝構造實作深拷貝,避免成員變量指針指派導緻的錯誤
strlen(it.get_s());
it.s);
mystring::~mystring()
[]s;//将構造函數配置設定的記憶體釋放
*mystring::get_s()
s;
mystring::set_s(const
(this->s
}else
len1
strlen(this->s);
len2
(len1
>
len2)
{
this->s[strlen(s)]
[]this->s;//由于成員變量s的空間不夠了,是以不要了
char[len2
1];//重新給成員變量s配置設定新空間
s);//給新空間指派
this->s[len2]
0;//新空間最後一個位元組為字元串結束标示符0
主函數的實作代碼:
str1("hello
world");
str2
str1;
str3.set_s("sdfsd");
str1.get_s()
//mystring
*str1
mystring::makestring();//預設調用的是null
mystring::makestring("hello
world");//預設調用的是null
<< str1->get_s()
mystring::deletestring();
*str3
mystring::makestring("aaaaaaa");
<< str3->get_s()
static變量是放到靜态記憶體區的,程式加載就存在,一直到程式退出才清理。
類的static成員和類的對象沒有直接關系,類的靜态成員是放到靜态記憶體區的,程式開始執行就存在,一直到程式結束才清理。
類的靜态成員變量不論類的執行個體有多少,但成員變量隻有一份。
單例的一個案例:
single_h
single
*p;
//構造函數被保護
single();
//通過方法的方式實作生成執行個體
*makesignle();
releasesingle();
單例的實作代碼:
"single.h"
*single::p
single::single(){}
*single::makesignle()
(p
//如果p為空,就執行個體化對象傳回,否則直接單例
p
single;
single::releasesingle()
main實作類
//執行個體化單例的例子
single::makesignle();
*p1
single::releasesingle();