文章目錄
- 一、友元
- 1.友元函式
- 2.友元類
- 二、C語言動態記憶體管理的方式
- 三、 C++記憶體管理方式
- 1.new/delete操作內置型別
- 2.new和delete操作自定義型別
- 四、 malloc/free和new/delete
- 1.共同點
- 2.不同點
- 感謝閱讀,如有錯誤請批評指正
一、友元
友元分為友元函式和友元類,
友元提供了一種突破封裝的方式,有時提供了便利,但是友元會增加耦合度,破壞了封裝,所以友元不宜多用,
1.友元函式
如果想要用cout直接輸出日期而不是用成員函式來間接輸出,就需要多載>>來實作,
注意cout的型別是ostream,呼叫的時候傳入cout,
代碼如下:
class Date
{
public:
void operator<<(ostream& out)//void operator<<(Date* this, ostream& out)
{
out << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
但是由于多載時第一個引數一定是隱含的this指標,所以在使用多載后的<<時需要如下使用,
代碼如下:
int main()
{
Date d1;
d1 << cout;//也即d1.operator<<(cout);
return 0;
}
這顯然不符合cout的使用習慣,同時代碼的可讀性很差,甚至不如一個間接的print函式,
于是有了一個問題:<<的多載寫在類內會導致代碼可讀性下降,寫在類外又無法訪問類的成員變數,
那么怎樣解決這個問題呢——用友元,
友元函式可以直接訪問類的私有成員,它是定義在類外部的普通函式,不屬于任何類,但需要在類的內部宣告,宣告時需要加friend關鍵字,
代碼如下:
class Date
{
//定義友元函式(在類內)
//只需在函式宣告前加上friend即可
friend void operator<<(ostream& out, const Date& d);
public:
Date(int year = 1970, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
void operator<<(ostream& out, const Date& d)
{
out << d._year << "-" << d._month << "-" << d._day << endl;
}
int main()
{
Date d1;
cout << d1;//即operator<<(cout, d1);
return 0;
}
但是由于operator<<回傳值是空,所以無法實作連續輸出,只需將operator<<的回傳值改為ostream&,即繼續回傳out,這樣每次輸出后的回傳值都是out,可支持連續輸出,
代碼如下:
class Date
{
friend ostream& operator<<(ostream& out, const Date& d);
public:
Date(int year = 1970, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "-" << d._month << "-" << d._day << endl;
return out;
}
int main()
{
Date d1;
Date d2(2021, 7, 21);
cout << d1 << d2;//可連續輸出
return 0;
}
輸入多載>>同理,
代碼如下:
class Date
{
public:
friend istream& operator>>(istream& in, Date& d);
private:
int _year;
int _month;
int _day;
};
//cin型別為istream
//回傳值為istream可支持連續輸入多個Date物件
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
注意:
(1)友元函式可訪問類的私有和保護成員,但不是類的成員函式,
(2)友元函式不能用const修飾,
(3)友元函式可以在類定義的任何地方宣告,不受類訪問限定符限制,
(4)一個函式可以是多個類的友元函式,
(5)友元函式的呼叫與普通函式的呼叫和原理相同,
2.友元類
友元類的所有成員函式都可以是另一個類的友元函式,都可以訪問另一個類中的非公有成員,
如下面的代碼中Date類中的成員函式想要訪問Time型別的物件_t的成員變數,則需要將Date類定義為Time類的友元,
代碼如下:
class Date
{
public:
Date(int year = 1970, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void SetTime()
{
_t._hour = 0;
_t._minute = 1;
_t._second = 1;
}
private:
int _year;
int _month;
int _day;
Time _t;
};
class Time
{
friend class Date;
public:
Time(int hour = 0, int minute = 1, int second = 1)
{
_hour = hour;
_minute = minute;
_second = second;
}
private:
int _hour;
int _minute;
int _second;
};
注意:
(1)友元關系是單向的,不具有交換性,
比如上述Time類和Date類,在Time類中宣告Date類為其友元類,那么可以在Date類中直接訪問Time
類的私有成員變數,但不能在Time類中訪問Date類中私有的成員變數,
(2)友元關系不能傳遞,
如果B是A的友元,C是B的友元,不能說明C是A的友元,
二、C語言動態記憶體管理的方式
關于C語言動態記憶體管理的相關知識請移步C語言動態記憶體管理,
三、 C++記憶體管理方式
通過new和delete運算子進行動態記憶體管理,
注意C語言中與動態記憶體相關的malloc,realloc,calloc和free是函式,而C++中的new和delete是運算子,
1.new/delete操作內置型別
new/delete和malloc/free針對內置型別沒有任何差別,只是寫法不一樣,
代碼如下:
void Test()
{
//注意new和delete的格式
//動態申請一個int型別的空間,不初始化
int* ptr1 = new int;
//動態申請一個double型別的空間并初始化為3.14
//注意可以直接初始化
double* ptr2 = new double(3.14);
//動態申請10個char型別的空間
char* ptr3 = new char[3];
delete ptr1;
delete ptr2;
delete[] ptr3;//不要忘記[]
}
注意:申請和釋放單個元素的空間,使用new和delete運算子,申請和釋放連續的空間,使用new[]和delete[], new和delete、new[]和delete[]一定要匹配,否則可能出問題,
2.new和delete操作自定義型別
代碼如下:
class ListNode
{
public:
ListNode(int val = 0)
:_val(val)
, _prev(nullptr)
, _next(nullptr)
{
cout << "呼叫建構式" << endl;
}
~ListNode()
{
cout << "呼叫解構式" << endl;
}
private:
int _val;
ListNode* _prev;
ListNode* _next;
};
int main()
{
ListNode* c = (ListNode*)malloc(sizeof(ListNode));
free(c);
ListNode* cpp = new ListNode;
delete cpp;
return 0;
}
除錯如下,可以觀察到malloc僅僅開出所需的空間,并不會對指標指向地址的成員變數進行初始化;而new不僅開出所需的空間,還會會對指標指向地址的成員變數進行初始化,
除錯結果如下:

運行如下,可以觀察到delete會呼叫自定義型別的解構式,而free不會,
運行如下:

在申請自定義型別的空間時,new會呼叫建構式,delete會呼叫解構式,而malloc與free不會,
四、 malloc/free和new/delete
1.共同點
從堆上申請空間,并且需要手動釋放,
2.不同點
(1)malloc和free是函式,new和delete是運算子
(2)malloc申請的空間不會初始化,new可以初始化
(3)malloc申請空間時,需要手動計算空間大小,new只需在其后跟上空間的型別即可
(4)malloc的回傳值為void*, 在使用時必須強轉,new不需要,因為new后跟的是空間的型別
(5)malloc申請空間失敗時,回傳的是NULL,因此使用時必須判空,new不需要,但是new需要捕獲例外
(6)申請自定義型別物件時,malloc/free只會開辟空間,不會呼叫建構式與解構式,而new在申請空間后會呼叫建構式完成物件的初始化,delete在釋放空間前會呼叫解構式完成空間中資源的清理
感謝閱讀,如有錯誤請批評指正
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/289580.html
標籤:其他
