參考網址:https://blog.csdn.net/zqixiao_09/article/details/51474556
參考網址:http://c.biancheng.net/cpp/biancheng/cpp/rumen/
1.類 class
類只是一個模板(Template),編譯後不佔用內存空間,所以在定義類時不能對成員變量進行初始化,因爲沒有地方存儲數據。只有在創建對象以後纔會給成員變量分配內存,這個時候就可以賦值了。
舉個栗子
class Student
{
public:
Student();
~Student();
private:
string name='\0';//錯誤不能初始化
int score;
};
當成員函數定義在類外時,就必須在函數名前面加上類名予以限定。::被稱爲域解析符(也稱作用域運算符或作用域限定符),用來連接類名和函數名,指明當前函數屬於哪個類。
成員函數必須先在類體中作原型聲明,然後在類外定義,也就是說類體的位置應在函數定義之前。
2.構造函數
1.構造函數主要:用來初始化和內存分配
2.構造函數的調用是強制性的,一旦在類中定義了構造函數,那麼創建對象時就一定要調用,不調用是錯誤的。如果有多個重載的構造函數,那麼創建對象時提供的實參必須和其中的一個構造函數匹配;反過來說,創建對象時只有一個構造函數會被調用。
3.構造函數的一項重要功能是對成員變量進行初始化,爲了達到這個目的,可以在構造函數的函數體中對成員變量一一賦值,還可以採用參數初始化表。
//採用參數初始化表
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ //TODO:}
注意,參數初始化順序與初始化表列出的變量的順序無關,它只與成員變量在類中聲明的順序有關。
舉個栗子
#include <iostream>
using namespace std;
class Demo{
private:
int m_a;
int m_b;
public:
Demo(int b);
void show();
};
Demo::Demo(int b): m_b(b), m_a(m_b){ }//-----------重點看這裏順序------//
void Demo::show(){ cout<<m_a<<", "<<m_b<<endl; }
int main(){
Demo obj(100);
obj.show();
return 0;
}
3.析構函數
new 創建的對象位於堆區,通過 delete 刪除時纔會調用析構函數;如果沒有 delete,析構函數就不會被執行。(先構造着後析構)
舉個栗子
#include <iostream>
#include <string>
using namespace std;
class Demo{
public:
Demo(string s);
~Demo();
private:
string m_s;
};
Demo::Demo(string s): m_s(s){ }
Demo::~Demo(){ cout<<m_s<<endl; }
void func(){
//局部對象
Demo obj1("1");
}
//全局對象
Demo obj2("2");
int main(){
//局部對象
Demo obj3("3");
//new創建的對象
Demo *pobj4 = new Demo("4");
func();
cout<<"main"<<endl;
return 0;
}
這個問題是考試重點一定要了解變量的分配時期和表示的範圍
變化一下把25行的func()移動到24行或者26行後面,聰明的你能知道運行結果嗎?不知道耶沒有關係的哦,你可以試着運行一下哦,記住一個
祕訣就是先構造着後析構,加上變量生存期。
你就可以掌握了。
4.靜態成員 static
聰明的你知道什麼時候用靜態成員嗎?當這個類的所有公用一個變量或者函數最好用靜態成員,只花銷一個空間。看到這是不是還是很模糊,那麼給你舉個最簡單的例子,要統計計科182班的總成績或者總人數,不管哪個變量訪問總成績的時候都是一樣的。
和靜態成員變量類似,靜態成員函數在聲明時要加 static,在定義時不能加 static static函數是全域函數(global
functions),但是像一個指定class的對象成員一樣被調用。它們只能夠引用static
數據,永遠不能引用class的非靜態成員。它們也不能夠使用關鍵字this,因爲this實際引用了一個對象指針,但這些
static函數卻不是任何object的成員,而是class的直接成員。
舉個栗子
#include <iostream>
using namespace std;
class Student{
public:
Student(char *name, int age, float score);
void show();
public: //聲明靜態成員函數
static int getTotal();
static float getPoints();
private:
static int m_total; //總人數
static float m_points; //總成績
private:
char *m_name;
int m_age;
float m_score;
};
int Student::m_total = 0;
float Student::m_points = 0.0;
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
m_total++;
m_points += score;
}
void Student::show(){
cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<endl;
}
//定義靜態成員函數
int Student::getTotal(){
return m_total;
}
float Student::getPoints(){
return m_points;
}
int main(){
(new Student("小明", 15, 90.6)) -> show();
(new Student("李磊", 16, 80.5)) -> show();
(new Student("張華", 16, 99.0)) -> show();
(new Student("王康", 14, 60.8)) -> show();
int total = Student::getTotal();
float points = Student::getPoints();
cout<<"當前共有"<<total<<"名學生,總成績是"<<points<<",平均分是"<<points/total<<endl;
return 0;
}
一個class的靜態數據成員也被稱作類變量"class variables",因爲它們的內容不依賴於某個對象,對同一個class的所有object具有相同的值。
例如,它可以被用作計算一個class聲明的objects的個數
舉個栗子
#include <iostream>
using namespace std;
class CDummy
{
public:
static int n;
CDummy () { n++; };
~CDummy () { n--; };
};
int CDummy::n = 0;
int main ()
{
CDummy a;
CDummy b[5];
CDummy * c = new CDummy;
cout << a.n << endl;
delete c;
cout << CDummy::n << endl;
return 0;
}
//上面代碼11行
int CDummy::n = 0;
初始化的時候才分配空間。
注意:static 成員變量的內存既不是在聲明類時分配,也不是在創建對象時分配,而是在(類外)初始化時分配。反過來說,沒有在類外初始化的
static 成員變量不能使用。
靜態成員函數與普通成員函數的根本區別在於:普通成員函數有 this
指針,可以訪問類中的任意成員;而靜態成員函數沒有 this 指針,只能訪問靜態成員(包括靜態成員變量和靜態成員函數)。
5.const成員變量
const 成員變量的用法和普通 const 變量的用法相似,只需要在聲明時加上 const 關鍵字。初始化 const 成員變量只有一種方法,就是通過參數初始化表
舉個栗子
#include<iostream>
using namespace std;
int main()
{
//初始化列表必須放在構造函數的後面
char a[]="hello",b[]="world";
char *p=a;
cout<<p[2]<<endl;
const char *p1=a;//數據不能改
p1=b;//可以修改指針
//p1[2]='w';不可行,不行修改指針指向的數據
cout<<p1[2]<<endl;
char *const p2=a;//指針不能移動
p2[2]='s';
//p2=b; 不可行
cout<<p2[2]<<endl;
const char *const p3=a;
//p3[2]='1';不可行
//p3=b;不可行
}
const
離變量名近就是用來修飾指針變量的,離變量名遠就是用來修飾指針指向的數據,如果近的和遠的都有,那麼就同時修飾指針變量以及它指向的數據。
一旦將對象定義爲常對象之後,不管是哪種形式,該對象就只能訪問被 const 修飾的成員了(包括 const 成員變量和 const 成員函數),因爲非 const 成員可能會修改對象的數據(編譯器也會這樣假設),C++禁止這樣做。
舉個栗子
#include <iostream>
using namespace std;
class Student{
public:
Student(char *name, int age, float score);
public:
void show();
char *getname() const;
int getage() const;
float getscore() const;
private:
char *m_name;
int m_age;
float m_score;
};
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(){
cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<endl;
}
char * Student::getname() const{
return m_name;
}
int Student::getage() const{
return m_age;
}
float Student::getscore() const{
return m_score;
}
int main(){
const Student stu("小明", 15, 90.6);
stu.show(); //error
cout<<stu.getname()<<"的年齡是"<<stu.getage()<<",成績是"<<stu.getscore()<<endl;
const Student *pstu = new Student("李磊", 16, 80.5);
//pstu -> show(); //error
cout<<pstu->getname()<<"的年齡是"<<pstu->getage()<<",成績是"<<pstu->getscore()<<endl;
return 0;
}
6.友元函數friend
舉個栗子
#include <iostream>
using namespace std;
class Student{
public:
Student(char *name, int age, float score);
public:
friend void show(Student *pstu); //將show()聲明爲友元函數
private:
char *m_name;
int m_age;
float m_score;
};
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
//非成員函數
void show(Student *pstu){
cout<<pstu->m_name<<"的年齡是 "<<pstu->m_age<<",成績是 "<<pstu->m_score<<endl;
}
int main(){
Student stu("小明", 15, 90.6);
show(&stu); //調用友元函數
Student *pstu = new Student("李磊", 16, 80.5);
show(pstu); //調用友元函數
return 0;
}
舉個栗子
#include <iostream>
using namespace std;
class Address; //提前聲明Address類
//聲明Student類
class Student{
public:
Student(char *name, int age, float score);
public:
void show(Address *addr);
private:
char *m_name;
int m_age;
float m_score;
};
//聲明Address類
class Address{
private:
char *m_province; //省份
char *m_city; //城市
char *m_district; //區(市區)
public:
Address(char *province, char *city, char *district);
//將Student類中的成員函數show()聲明爲友元函數
friend void Student::show(Address *addr);
};
//實現Student類
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(Address *addr){
cout<<m_name<<"的年齡是 "<<m_age<<",成績是 "<<m_score<<endl;
cout<<"家庭住址:"<<addr->m_province<<"省"<<addr->m_city<<"市"<<addr->m_district<<"區"<<endl;
}
//實現Address類
Address::Address(char *province, char *city, char *district){
m_province = province;
m_city = city;
m_district = district;
}
int main(){
Student stu("小明", 16, 95.5f);
Address addr("陝西", "西安", "雁塔");
stu.show(&addr);
Student *pstu = new Student("李磊", 16, 80.5);
Address *paddr = new Address("河北", "衡水", "桃城");
pstu -> show(paddr);
return 0;
}
友元類
不僅可以將一個函數聲明爲一個類的“朋友”,還可以將整個類聲明爲另一個類的“朋友”,這就是友元類。友元類中的所有成員函數都是另外一個類的友元函數。
例如將類 B 聲明爲類 A 的友元類,那麼類 B 中的所有成員函數都是類 A 的友元函數,可以訪問類 A 的所有成員,包括
public、protected、private 屬性的。