上一篇我們學習了C++的命名空間,這篇我們來了解一下C++的構造和析構函數
廢話不多說,開始擼碼
正文
構造函數、析構函數、拷貝構造函數
來個簡單的例子,了解一下構造和析構的寫法
class Teacher{
public:
int age;
public:
Teacher(){
cout << "無參構造函數" << endl;
}
~Teacher(){
cout << "析構函數" << endl;
}
};
當類沒有構造函數的時候默認會有一個無參的構造函數,構造函數的作用是初始化變量,析構函數則釋放資源
既然有了構造函數,那怎么創建對象呢?
無參構造: Teacher t;
有參構造: Teacher t1("lypop", 21);
Teacher t2 = Teacher("lypop", 21);
創建指針: Teacher *tt = new Teacher("lypop",21);
對于析構函數的調用,我們將創建放在一個方法里面,當方法執行結束便會執行析構函數
class Teacher{
private:
char *name;
int age;
public:
Teacher(){
this->name = (char*)malloc(100);
strcpy(name, "lypop");
age = 20;
cout << "無參構造函數" << endl;
}
//析構函數
~Teacher(){
cout << "析構" << endl;
//釋放內存
free(this->name);
}
};
void func2(){
Teacher t;
}
我們只需要在析構函數中釋放相應的資源
除了構造函數和析構函數,類里面有個默認的拷貝構造函數,它只是一種值拷貝,當類中有指針屬性的時候容易發生崩潰。所以當我們類中有指針需要在析構函數釋放資源的時候,拷貝構造函數都使用深拷貝
下面來看一下值拷貝(淺拷貝)
class Teacher{
private:
char *name;
int age;
public:
Teacher(char *name, int age){
this->name = (char*)malloc(100);
strcpy(this->name,name);
this->age = age;
cout << "有參構造函數" << endl;
}
~Teacher(){
cout << "析構" << endl;
//釋放內存
free(this->name);
}
};
void func(){
Teacher t1("rose", 20);
Teacher t2 = t1;//這時候會調用默認的拷貝構造函數
}
當func執行完畢之后就會調用兩次析構,因為只是簡單的值拷貝,name指針指向的是同一塊內存地址,當第一個被釋放掉在釋放第二個的時候就會出錯。所以需要解決這種就需要深拷貝,也就是重寫拷貝構造函數為name重新開辟一塊內存地址
//深拷貝
Teacher(const Teacher &obj){
//復制name屬性
int len = strlen(obj.name);
this->name = (char*)malloc(len+1);
strcpy(this->name,obj.name);
this->age = obj.age;
}
拷貝構造函數被調用的場景:
- 聲明時賦值
- 作為參數傳入,實參給形參賦值
- 作為函數返回值返回,給變量初始化賦值
C和C++創建指針和釋放資源
C 創建 int *p1 = (int*)malloc(sizeof(int) * 10);
釋放 free(p1);
C++創建 int *p2 = new int[10];
釋放 delete[] p2;//釋放數組指針 delete p;//釋放指針
C++訪問靜態屬性和方法
通過類名::來訪問,也可以通過類對象來訪問
int Teacher::total = 9;
Teacher::total++;
Teacher::count();
常量對象、常函數
Teacher *const this;能改變指針指向的內容,不能改變指針的值
const Teacher* const this;既不能改變指針的值,又不能改變指針指向的內容
常量對象只能調用常量函數,不能調用非常量函數。常函數當前對象不能被修改,防止數據成員被非法訪問
class Teacher{
void myprint() const{
}
};
void main(){
const Teacher t1("aaa",22);
t.myprint();
system("pause");
}
友元函數、友元類
友元函數的實現,在友元函數中可以訪問私有的屬性
class A{
friend void modify_i(A *p, int a);
private:
int i;
};
void modify_i(A *p, int a){
p->i = a;
}
友元類中可以訪問友元對象所在類的所有成員
class A{
friend class B;
private:
int i;
};
class B{
public:
//B這個友元類可以訪問A類的任何成員
void accessAny(){
a.i = 30;
}
private:
A a;
};
運算符重載
-
類外進行運算符重載
class Point{ public: int x; int y; public: Point(int x = 0, int y = 0){ this->x = x; this->y = y; } void myprint(){ cout << x << "," << y << endl; } }; Point operator+(Point &p1, Point &p2){ Point tmp(p1.x+p2.x,p1.y+p2.y); return tmp; } Point operator-(Point &p1, Point &p2){ Point tmp(p1.x - p2.x, p1.y - p2.y); return tmp; }
-
類內進行運算符重載
class Point{ public: int x; int y; public: Point(int x = 0, int y = 0){ this->x = x; this->y = y; } //成員函數,運算符重載 Point operator+(Point &p2){ Point tmp(this->x + p2.x, this->y + p2.y); return tmp; } void myprint(){ cout << x << "," << y << endl; } };
-
當屬性私有的時候需要使用友元函數實現運算符重載
class Point{ friend Point operator+(Point &p1, Point &p2); private: int x; int y; public: Point(int x = 0, int y = 0){ this->x = x; this->y = y; } void myprint(){ cout << x << "," << y << endl; } }; Point operator+(Point &p1, Point &p2){ Point tmp(p1.x + p2.x, p1.y + p2.y); return tmp; }
但是運算符重載的本質還是函數的調用,至此C++的類就總結到這里,謝謝不耐其煩的看完。