目錄
友元:
友元函數:
示例:
友元類:
示例:
優點:
注意事項:
運算符重載:
注意:
示例:
友元:
C++中如果想要外部函數或者類對一個類的private(私有成員)和protected(保護成員),可以通過使用friend關鍵字對其進行聲明。
聲明位置靈活,可以在類內任何訪問區域進行友元聲明。
友元函數:
友元函數一般在運算符重載和需要訪問私有數據的全局函數進行使用。友元函數是聲明在類內的非成員函數,可以訪問該類的所有成員(包括私有和保護成員)。
示例:
通過友元函數訪問Student類的私有成員_name,在類內聲明GetStudentName()友元函數,在類外進行定義來。
#include <iostream>
#include <string>
#include <thread>class Student {friend void GetStudentName(const Student& student);
public:Student():_name(""),_age(0),_data(new int(0)) {std::cout << "無參構造" << std::endl;}Student(std::string name, int age,int number):_name(name),_age(age),_data(new int(number)) {std::cout << "有參構造" << std::endl;}Student(const Student &student):_name(student._name),_age(student._age) {//const可以加可以不加,主要是為了防止對參數進行修改,但是&是必須加std::cout << "拷貝構造" << std::endl;_data = new int();*_data = *student._data;}Student(Student && student):_name(std::move(student._name)),_age(student._age),_thread(std::move(student._thread)){std::cout << "移動構造" << std::endl;_data = new int();*_data = std::move(*(student._data));}~Student() {std::cout << "析構函數" << std::endl;delete _data;}void GetTarget() {std::cout << "獲取的target的值:";std::cout << _target << std::endl;std::cout << std::endl;}void ModifyTarget(int target) {std::cout << "修改target之后的值:";_target = target;std::cout << _target<<std::endl;}void GetName() {std::cout << _name << std::endl;}void GetAge() {std::cout << _age << std::endl;}void GetData() {std::cout << _data << std::endl;}
private:std::string _name;int _age;static int _target;//類內聲明,類外初始化std::thread _thread;int* _data;
};
int Student::_target = 100;void GetStudentName(const Student& student) {std::cout << student._name << std::endl;
}int main() {Student student1("小明",16,10);GetStudentName(student1);return 0;
}
運行結果:
友元類:
友元類是其所有成員均可以訪問另一個類的私有成員和保護成員的類。需要注意的是:
類A聲明為類B為友元,不意味著類B自動授予類A的訪問權限,類B可以訪問類A的私有成員和保護成員,但是類A不是類B的友元,所以不能訪問類B的私有成員和保護成員。
如果類B是類A的友元類,同時類C是類B的友元,類C是不會自動成為類A的友元,也就是不會有傳遞性。
基類的派生類不會繼承基類的友元關系,也就是沒有繼承性。
示例:
創建一個獲取Student類的私有成員_name的類,在其成員函數中定義獲取的成員函數func()。
#include <iostream>
#include <string>
#include <thread>class Student {friend void GetStudentName(const Student& student);
public:Student():_name(""),_age(0),_data(new int(0)) {std::cout << "無參構造" << std::endl;}Student(std::string name, int age,int number):_name(name),_age(age),_data(new int(number)) {std::cout << "有參構造" << std::endl;}Student(const Student &student):_name(student._name),_age(student._age) {//const可以加可以不加,主要是為了防止對參數進行修改,但是&是必須加std::cout << "拷貝構造" << std::endl;_data = new int();*_data = *student._data;}Student(Student && student):_name(std::move(student._name)),_age(student._age),_thread(std::move(student._thread)){std::cout << "移動構造" << std::endl;_data = new int();_data = std::move(student._data);}~Student() {std::cout << "析構函數" << std::endl;delete _data;}void GetTarget() {std::cout << "獲取的target的值:";std::cout << _target << std::endl;std::cout << std::endl;}void ModifyTarget(int target) {std::cout << "修改target之后的值:";_target = target;std::cout << _target<<std::endl;}Student operator+(const Student& other)const {Student temp;temp._age=this->_age + other._age;temp._data = new int(*this->_data + *other._data);return temp;}Student& operator=(const Student& other) {if (this == &other) {return *this;}delete _data;this->_name = other._name;this->_age = other._age;this->_data = new int();*this->_data = *other._data;std::cout << "拷貝賦值運算符" << std::endl;return *this;}Student& operator=(Student&& other)noexcept {if (this == &other) {return *this;}delete this->_data;this->_name = std::move(other._name);this->_age = other._age;this->_data = other._data;other._data = nullptr;std::cout << "移動賦值運算符" << std::endl;return *this;}Student& operator++() {this->_age++;(*this->_data)++;return *this;}const Student operator++(int) {Student temp(*this);this->_age++;(*this->_data)++;return temp;}friend std::ostream& operator<<(std::ostream& os, Student& other);
private:std::string _name;int _age;static int _target;//類內聲明,類外初始化std::thread _thread;int* _data;
};
int Student::_target = 100;void GetStudentName(const Student& student) {std::cout << student._name << std::endl;
}std::ostream& operator<<(std::ostream& os, Student& other) {os << other._name << " "<< other._age << " "<< *other._data << std::endl;return os;
}int main() {std::cout << "構造student1和student2:" << std::endl;Student student1("小明",16,10);Student student2("小剛", 10, 10);std::cout << student2;std::cout << student1;std::cout << std::endl << "構造student3:" << std::endl;Student student3;student3=student1 + student2;std::cout << student3;std::cout <<std::endl<< "對student1進行前置++,對student2進行后置++:" << std::endl;Student student5=++student1;Student student6=student2++;std::cout << "前置++:" << std::endl;std::cout << student1;std::cout << student5;std::cout << "后置++:" << std::endl;std::cout << student2;std::cout << student6;std::cout << "移動賦值運算符:" << std::endl;Student student7;student7=std::move(student2);std::cout << student7;return 0;
}
運行結果:
優點:
避免了共有接口簡介訪問私有數據,支持特殊的場景,比如運算符重載等。
注意事項:
友元會破壞類的封裝性,不能夠通過繼承或者嵌套自動傳遞,會導致代碼的耦合度增加,維護難度上升。
優先使用成員函數或者公有接口,在必要時使用友元,盡量使用友元函數不使用友元類,減少權限的開放。
運算符重載:
通過成員函數或者友元函數重新定義運算符對自定義類型的操作行為。
注意:
運算符重載不能夠創建新的運算符。
不能夠改變運算符的優先級和結合性。
并非所有的運算符都能夠進行重載,比如成員當問運算符、成員指針運算符、作用域解析運算符、條件運算符、sizeof和typeid運算符不能夠進行重載。
示例:
對"+"、"<<"、"="、"前置++"、"后置++"進行重載。"-"、"*"、和"/"和"+"是一樣的思路。注意區分前置++和后置++的區別,還需要注意重載時,前置++和后置++的函數參數區別。移動語義操作中一定注意將被移動對象的指針置空,防止出現雙重釋放或者懸空指針問題。
#include <iostream>
#include <string>
#include <thread>class Student {friend void GetStudentName(const Student& student);
public:Student():_name(""),_age(0),_data(new int(0)) {std::cout << "無參構造" << std::endl;}Student(std::string name, int age,int number):_name(name),_age(age),_data(new int(number)) {std::cout << "有參構造" << std::endl;}Student(const Student &student):_name(student._name),_age(student._age) {//const可以加可以不加,主要是為了防止對參數進行修改,但是&是必須加std::cout << "拷貝構造" << std::endl;_data = new int();*_data = *student._data;}Student(Student && student):_name(std::move(student._name)),_age(student._age),_thread(std::move(student._thread)){std::cout << "移動構造" << std::endl;_data = new int();_data = std::move(student._data);}~Student() {std::cout << "析構函數" << std::endl;delete _data;}void GetTarget() {std::cout << "獲取的target的值:";std::cout << _target << std::endl;std::cout << std::endl;}void ModifyTarget(int target) {std::cout << "修改target之后的值:";_target = target;std::cout << _target<<std::endl;}Student operator+(const Student& other)const {Student temp;temp._age=this->_age + other._age;temp._data = new int(*this->_data + *other._data);return temp;}Student& operator=(const Student& other) {if (this == &other) {return *this;}delete _data;this->_name = other._name;this->_age = other._age;this->_data = new int();*this->_data = *other._data;std::cout << "拷貝賦值運算符" << std::endl;return *this;}Student& operator=(Student&& other)noexcept {if (this == &other) {return *this;}delete this->_data;this->_name = std::move(other._name);this->_age = other._age;this->_data = other._data;other._data = nullptr;std::cout << "移動賦值運算符" << std::endl;return *this;}Student& operator++() {this->_age++;(*this->_data)++;return *this;}const Student operator++(int) {Student temp(*this);this->_age++;(*this->_data)++;return temp;}friend std::ostream& operator<<(std::ostream& os, Student& other);
private:std::string _name;int _age;static int _target;//類內聲明,類外初始化std::thread _thread;int* _data;
};
int Student::_target = 100;void GetStudentName(const Student& student) {std::cout << student._name << std::endl;
}std::ostream& operator<<(std::ostream& os, Student& other) {os << other._name << " "<< other._age << " "<< *other._data << std::endl;return os;
}int main() {std::cout << "構造student1和student2:" << std::endl;Student student1("小明",16,10);Student student2("小剛", 10, 10);std::cout << student2;std::cout << student1;std::cout << std::endl << "構造student3:" << std::endl;Student student3;student3=student1 + student2;std::cout << student3;std::cout <<std::endl<< "對student1進行前置++,對student2進行后置++:" << std::endl;Student student5=++student1;Student student6=student2++;std::cout << "前置++:" << std::endl;std::cout << student1;std::cout << student5;std::cout << "后置++:" << std::endl;std::cout << student2;std::cout << student6;std::cout << "移動賦值運算符:" << std::endl;Student student7;student7=std::move(student2);std::cout << student7;return 0;
}
運行結果: