权限管理是 c++ 的一大特点,面向对象语言封装的特性也给权限管理带了了方便。c++ 中的权限主要有 3 种:public,private,protected。类中的函数和属性默认是 private 的,类的继承关系默认也是 private 的。
public,private,protected 的使用场景有两个:修饰类成员以及修饰类的继承关系。本文先记录这 3 个权限修饰符修饰类成员以及继承关系,最后再记录 friend 的使用。
1 类成员
类内部 | 子类内部 | 通过对象 | |
public | 可以访问 | 可以访问 | 可以访问 |
private | 可以访问 | 不可以访问 | 不可以访问 |
protected | 可以访问 | 可以访问 | 不可以访问 |
1.1 public
public 权限是最宽松的,被修饰为 public 的成员在类内部可以直接访问,也可以在类外部通过对象来访问,当然也可以在类的派生类中访问,权限没有限制。
下边的代码, Base 类中的 Do() 函数是 public 的,属性 a_ 是 public 的,这两个方法和属性在类内部,子类中,类外部都可以访问。
最宽松的权限管理,没有什么限制。
#include <iostream>
#include <string>class Base {
public:Base(int a) {a_ = a;std::cout << "Base(), a_ = " << a_ << std::endl;Do();};~Base() {std::cout << "~Base(), a_ = " << a_ << std::endl;};void Do() {std::cout << "Base() Do(), a_ = " << a_ << std::endl;};public:int a_;
};class Derived : public Base {
public:Derived() : Base(50) {a_ = 100;std::cout << "Derived(), a_ = " << a_ << std::endl;};~Derived() {std::cout << "~Derived(), a_ = " << a_ << std::endl;};
};int main() {Base b(1);b.Do();Derived d;d.Do();b.a_ = 12;b.Do();d.a_ = 20;d.Do();return 0;
}
1.2 private
如下代码,将 Base() 中的 Do() 函数,以及属性 a_ 的权限改成了 private。private 权限的函数或者属性只能在类内部访问,不能在类外部访问,在子类中也不能访问。
最严格的管理,最隐秘的隐私,自己的孩子都不知道,外人当然不知道。
技术来源于生活。
#include <iostream>
#include <string>class Base {
public:Base(int a) {a_ = a;std::cout << "Base(), a_ = " << a_ << std::endl;Do();};~Base() {std::cout << "~Base(), a_ = " << a_ << std::endl;};private:void Do() {std::cout << "Base() Do(), a_ = " << a_ << std::endl;};private:int a_;
};class Derived : public Base {
public:Derived() : Base(50) {a_ = 100; // 编译错误,private 属性只能在类内部访问,子类不能方位std::cout << "Derived(), a_ = " << a_ << std::endl; // 编译错误};~Derived() {std::cout << "~Derived(), a_ = " << a_ << std::endl; // 编译错误};
};int main() {Base b(1);b.Do(); // 编译错误Derived d;d.Do(); // 编译错误b.a_ = 12; // 编译错误b.Do(); // 编译错误d.a_ = 20; // 编译错误d.Do(); // 编译错误return 0;
}
1.3 protected
protected 权限管理介于 public 和 private 之间。protected 权限的函数或者属性在类内部能访问,在派生类的内部也能访问,但是在类外部通过对象不能访问。
#include <iostream>
#include <string>class Base {
public:Base(int a) {a_ = a;std::cout << "Base(), a_ = " << a_ << std::endl;Do();};~Base() {std::cout << "~Base(), a_ = " << a_ << std::endl;};protected:void Do() {std::cout << "Base() Do(), a_ = " << a_ << std::endl;};protected:int a_;
};class Derived : public Base {
public:Derived() : Base(50) {a_ = 100;std::cout << "Derived(), a_ = " << a_ << std::endl;Do();};~Derived() {std::cout << "~Derived(), a_ = " << a_ << std::endl;};
};int main() {Base b(1);b.Do(); // 编译错误Derived d;d.Do(); // 编译错误b.a_ = 12; // 编译错误b.Do(); // 编译错误d.a_ = 20; // 编译错误d.Do(); // 编译错误return 0;
}
2 继承
在类继承的时候,如果不指定权限,默认是 private 继承。
基类 public 成员 | 基类 private 成员 | 基类 protected 成员 | |
public 继承 | 在子类中仍为 public | 在子类中不可见 | 在子类中仍为 protected |
private 继承 | 在子类中变为 private | 在子类中不可见 | 在子类中变为 private |
protected 继承 | 在子类中变为 protected | 在子类中不可见 | 在子类中仍为 protected |
2.1 public
public 继承,在子类中能访问父类的 protected 成员,但是不能访问 private 成员。
在类外边通过对象,也不能访问 protected 成员和 private 成员。
#include <iostream>
#include <string>class Base {
public:Base() {std::cout << "Base()" << std::endl;};~Base() {std::cout << "~Base()" << std::endl;};void PublicDo() {std::cout << "Base() public do" << std::endl;}int public_a_;private:void PrivateDo() {std::cout << "Base() private do" << std::endl;}int private_a_;protected:void ProtectedDo() {std::cout << "Base() protected do" << std::endl;}int protected_a_;
};class Derived : public Base {
public:Derived() {std::cout << "Derived()" << std::endl;std::cout << "public a: " << public_a_ << std::endl;std::cout << "private a: " << private_a_ << std::endl; // 编译错误}~Derived() {std::cout << "~Derived()" << std::endl;}void DerivedDo() {PublicDo();PrivateDo(); // 编译错误ProtectedDo();}
};int main() {Base b;b.PublicDo();b.PrivateDo(); // 编译错误b.ProtectedDo(); // 编译错误b.public_a_ = 10;b.private_do_ = 20; // 编译错误b.protected_do_ = 30; // 编译错误Derived d;d.DerivedDo();return 0;
}
2.2 private
private 继承,父类的 public 成员和 protected 成员在子类中都成为 private 属性,在子类内可以访问,不能通过对象来访问,子类再派生的类也不能访问;子类中不能访问父类中的 private 成员。
#include <iostream>
#include <string>class Base {
public:Base() {std::cout << "Base()" << std::endl;};~Base() {std::cout << "~Base()" << std::endl;};void PublicDo() {std::cout << "Base() public do" << std::endl;}int public_a_;private:void PrivateDo() {std::cout << "Base() private do" << std::endl;}int private_a_;protected:void ProtectedDo() {std::cout << "Base() protected do" << std::endl;}int protected_a_;
};class Derived : private Base {
public:Derived() {std::cout << "Derived()" << std::endl;std::cout << "public a: " << public_a_ << std::endl;// std::cout << "private a: " << private_a_ << std::endl; // 编译错误}~Derived() {std::cout << "~Derived()" << std::endl;}void DerivedDo() {PublicDo();// PrivateDo(); // 编译错误ProtectedDo();}
};int main() {Base b;b.PublicDo();// b.PrivateDo(); // 编译错误// b.ProtectedDo(); // 编译错误b.public_a_ = 10;// b.private_do_ = 20; // 编译错误// b.protected_do_ = 30; // 编译错误Derived d;d.DerivedDo();return 0;
}
2.3 protected
父类中的 public 成员,在子类中变为 protected 属性;protected 和 private 属性保持不变
#include <iostream>
#include <string>class Base {
public:Base() {std::cout << "Base()" << std::endl;};~Base() {std::cout << "~Base()" << std::endl;};void PublicDo() {std::cout << "Base() public do" << std::endl;}int public_a_;private:void PrivateDo() {std::cout << "Base() private do" << std::endl;}int private_a_;protected:void ProtectedDo() {std::cout << "Base() protected do" << std::endl;}int protected_a_;
};class Derived : protected Base {
public:Derived() {std::cout << "Derived()" << std::endl;std::cout << "public a: " << public_a_ << std::endl;std::cout << "private a: " << private_a_ << std::endl; // 编译错误}~Derived() {std::cout << "~Derived()" << std::endl;}void DerivedDo() {PublicDo();PrivateDo(); // 编译错误ProtectedDo();}
};int main() {Base b;b.PublicDo();b.PrivateDo(); // 编译错误b.ProtectedDo(); // 编译错误b.public_a_ = 10;b.private_do_ = 20; // 编译错误b.protected_do_ = 30; // 编译错误Derived d;d.DerivedDo();return 0;
}
3 friend
friend 是说一个类对另一个函数或者另一个类的认证,如果一个类 A 中认证一个不是 A 成员函数的函数 F 为 friend 或者另一个类 B 为 friend,那么 F 或者 B 都可以访问 A 的私有成员。
给固化的权限管理增加了一些灵活性。
3.1 友元函数
(1)友元函数可以访问类的 public 成员,private 成员,protected 成员
(2) 友元函数可以声明在类的 public 中,private 中,protected 中,如代码中的 PhoneTest(),PhoneTest1(),PhoneTest2(),效果是一样的
(3)友元函数可以是一个独立的函数,也可以定义在类中(其实不属于类),也可以是另一个类的成员函数
#include <iostream>
#include <string>class Phone;
class Work {
public:void Do(Phone phone);
};class Phone {
public:Phone() {std::cout << "Phone()" << std::endl;}~Phone() {std::cout << "~Phone()" << std::endl;}void PublicCallUp() {std::cout << "PublicCallUp()" << std::endl;}int public_a_ = 10;friend void PhoneTest(Phone phone);friend void Work::Do(Phone phone);friend void InnerFriend(Phone phone) {std::cout << "InnerFriend()" << std::endl;phone.Print();phone.PublicCallUp();phone.PrivateCallUp();phone.ProtectedCallUp();phone.public_a_ = 11;phone.private_a_ = 21;phone.protected_a_ = 31;phone.Print();}private:void PrivateCallUp() {std::cout << "PrivateCallUp)" << std::endl;}void Print() {std::cout << "public a: " << public_a_ << std::endl;std::cout << "private a: " << private_a_ << std::endl;std::cout << "protected a: " << protected_a_ << std::endl;}int private_a_ = 20;friend void PhoneTest1(Phone phone);protected:void ProtectedCallUp() {std::cout << "ProtectedCallUp()" << std::endl;}int protected_a_ = 30;friend void PhoneTest2(Phone phone);
};void Work::Do(Phone phone) {std::cout << "Work() Do()" << std::endl;phone.Print();phone.PublicCallUp();phone.PrivateCallUp();phone.ProtectedCallUp();phone.public_a_ = 11;phone.private_a_ = 21;phone.protected_a_ = 31;phone.Print();}void PhoneTest(Phone phone) {std::cout << "PhoneTest" << std::endl;phone.Print();phone.PublicCallUp();phone.PrivateCallUp();phone.ProtectedCallUp();phone.public_a_ = 11;phone.private_a_ = 21;phone.protected_a_ = 31;phone.Print();
}void PhoneTest1(Phone phone) {std::cout << "PhoneTest1" << std::endl;phone.Print();phone.PublicCallUp();phone.PrivateCallUp();phone.ProtectedCallUp();phone.public_a_ = 11;phone.private_a_ = 21;phone.protected_a_ = 31;phone.Print();
}void PhoneTest2(Phone phone) {std::cout << "PhoneTest2" << std::endl;phone.Print();phone.PublicCallUp();phone.PrivateCallUp();phone.ProtectedCallUp();phone.public_a_ = 11;phone.private_a_ = 21;phone.protected_a_ = 31;phone.Print();
}int main() {Phone phone;PhoneTest(phone);PhoneTest1(phone);PhoneTest2(phone);Work work;work.Do(phone);return 0;
}
3.2 友元类
友元类中的函数,不管是 public,还是 private 还是 protected 的,都可以访问类的成员(public,private,protected)。
#include <iostream>
#include <string>class Phone;
class Work {
public:void PublicDo(Phone phone);private:void PrivateDo(Phone phone);protected:void ProtectedDo(Phone phone);
};class Phone {
public:Phone() {std::cout << "Phone()" << std::endl;}~Phone() {std::cout << "~Phone()" << std::endl;}void PublicCallUp() {std::cout << "PublicCallUp()" << std::endl;}int public_a_ = 10;friend class Work;private:void PrivateCallUp() {std::cout << "PrivateCallUp)" << std::endl;}void Print() {std::cout << "public a: " << public_a_ << std::endl;std::cout << "private a: " << private_a_ << std::endl;std::cout << "protected a: " << protected_a_ << std::endl;}int private_a_ = 20;protected:void ProtectedCallUp() {std::cout << "ProtectedCallUp()" << std::endl;}int protected_a_ = 30;};void Work::PublicDo(Phone phone) {std::cout << "Work() PublicDo()" << std::endl;phone.Print();phone.PublicCallUp();phone.PrivateCallUp();phone.ProtectedCallUp();phone.public_a_ = 11;phone.private_a_ = 21;phone.protected_a_ = 31;phone.Print();PrivateDo(phone);ProtectedDo(phone);
}void Work::PrivateDo(Phone phone) {std::cout << "Work() PrivateDo()" << std::endl;phone.Print();phone.PublicCallUp();phone.PrivateCallUp();phone.ProtectedCallUp();phone.public_a_ = 11;phone.private_a_ = 21;phone.protected_a_ = 31;phone.Print();
}void Work::ProtectedDo(Phone phone) {std::cout << "Work() ProtectedDo()" << std::endl;phone.Print();phone.PublicCallUp();phone.PrivateCallUp();phone.ProtectedCallUp();phone.public_a_ = 11;phone.private_a_ = 21;phone.protected_a_ = 31;phone.Print();
}int main() {Phone phone;Work work;work.PublicDo(phone);// work.PrivateDo(phone);// work.ProtectedDo(phone);return 0;
}