访问说明符可以控制类中的成员的访问权限。
使用public修饰的类的成员,类的用户可以直接访问。
使用private修饰的类的成员,只有成员函数可以访问,类的用户是没法访问的。
C++没有限制类中定义访问说明符的数量和位置,可以随处添加,一个访问说明符的修饰范围是,它声明的位置开始到类的下一个访问说明符。
C++中有两个关键字可以定义类,就是class和struct,他们的唯一区别在于class定义类的默认的访问权限是private,struct定义的类默认的访问权限是public。
练习
7.16
没有数量和位置的限制,如果成员函数或者数据成员需要让类的使用者显式的使用,那么就是用public访问说明符,一般情况下,数据成员都是private,还有一些仅在类内部使用的函数也可以使用private访问限定符修饰
7.17
默认的访问权限不一样
7.18
封装就是隐藏细节,封装可以让用户无需关注类的实现细节,直接调用接口。这还在一定程度上保证了类的安全性,让类的使用者不能直接修改某些数据成员。
7.19
struct Person {
private:
string name;
string address;
public:
string get_info()const{
return "name:" + name + "\n address:" + address;
}
Person(const string &n, const string &address) :name(n), address(address) {};
};
为了防止用户随意修改数据成员,所以数据成员都使用private访问限定符
而成员函数则使用public。
7.2.1 友元
一般情况下,数据成员会声明为private,这样在使用类的代码时,用户时无法直接访问数据成员的。
但是对于某些函数,它是类的接口,却不是类的成员,这些类往往会直接访问类的数据成员。为了解决在类的外部无法访问private修饰的数据成员和成员函数。
C++提供了友元friend
如果把一个函数在类中声明为友元,那么这个函数就可以直接访问了类的private修饰的成员了。
就像这样。
struct Person {
friend istream &input(istream& temp_cin, Person& p);
friend ostream & print(ostream& temp_cout, const Person &p);
private:
string name;
string address;
public:
string get_info()const{
return "name:" + name + "\n address:" + address;
}
Person()=default;
Person(const string &n, const string &address) :name(n), address(address) {};
};
istream &input(istream& temp_cin, Person& p) {
temp_cin >> p.name >> p.address;
return temp_cin;
}
ostream & print(ostream& temp_cout,const Person &p) {
temp_cout << p.name << "," << p.address << endl;
return temp_cout;
}
要注意的是,friend修饰的外部函数,仅仅表示i这个函数是友元的,不算是声明,所以需要在类的外部单独的声明。。
练习
7.20
如果某一个外部函数需要调用类的private成员,就需要将该函数声明为这个类的友元函数。
好处在于,对于某些是类的接口,却不是类的成员函数的函数,可以直接访问类的数据成员。
坏处在于,这等于在破坏封装性,友元函数可以直接访问类的private成员,带来了不安全性。
7.21
struct Sales_data
{
friend istream& input(istream& temp_input, Sales_data& data);
friend ostream& print(ostream& temp_cout, const Sales_data& data);
friend Sales_data add(Sales_data &data1, const Sales_data & data2);
private:
string bookNo;
unsigned units_sold=0;
double revenue = 0.0;
public:
string isbn() const { return bookNo; };
Sales_data& combine(const Sales_data& );
double avg_price()const;
//构造函数
//1.默认构造函数
Sales_data() =default;
//2.仅初始化isbn
Sales_data(const string& isbn) :bookNo(isbn) {};
//3.数据成员都初始化
Sales_data(const string& isbn, unsigned u, double p) :bookNo(isbn), units_sold(u), revenue(u*p) {};
//4.使用流来初始化
Sales_data(istream& temp_input) {
input(temp_input,*this);
};
};
7.22
上面总结中的代码就是