权限管理是 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;
}