[c++] public, private, protected, friend

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/701633.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

apidoc接口文档的自动更新与发布

文章目录 一、概述二、环境准备三、接口文档生成1. 下载源码2. 初始化3.执行 四、文档发布五&#xff0c;配置定时运行六&#xff0c;docker运行七&#xff0c;不足与优化分析 一、概述 最近忙于某开源项目的接口文档整理&#xff0c;采用了apidoc来整理生成接口文档。 apidoc…

深度学习系列59:文字识别

1. 简单文本&#xff1a; 使用google加的tesseract&#xff0c;效果不错。 首先安装tesseract&#xff0c;在mac直接brew install即可。 python调用代码&#xff1a; import pytesseract from PIL import Image img Image.open(1.png) pytesseract.image_to_string(img, lan…

MES管理系统生产过程控制的核心要素

MES&#xff08;制造执行系统&#xff09;是为优化制造业生产过程和管理而设计的软件系统&#xff0c;其核心要素包括&#xff1a; 工单管理&#xff1a;工单管理是MES系统最基本的功能之一&#xff0c;它可以跟踪和管理各种类型的工单&#xff0c;如生产工单、维修工单和质量…

解释 C++ 中的虚拟继承(Virtual Inheritance)

解释 C 中的虚拟继承&#xff08;Virtual Inheritance&#xff09; 在 C 中&#xff0c;虚拟继承&#xff08;Virtual Inheritance&#xff09;是一种特殊的继承方式&#xff0c;用于解决多继承带来的菱形继承&#xff08;Diamond Inheritance&#xff09;问题。虚拟继承主要通…

Spring篇----第六篇

系列文章目录 文章目录 系列文章目录前言一、spring 支持集中 bean scope?二、spring bean 容器的生命周期是什么样的?三、什么是 spring 的内部 bean?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男…

Java EE改名Jakarta EE,jakarta对程序开发的影响

一、前言 很多Java程序员在使用新版本的Spring6或者springboot3版本的时候&#xff0c;发现了一些叫jakarta的包。我在阅读开源工作流引擎camunda源代码的时候&#xff0c;也发展了大量jakarta的工程包。 比如&#xff1a;camunda的webapps编译工程就提供了2种方式javax和jaka…

SCI一区 | Matlab实现ST-CNN-MATT基于S变换时频图和卷积网络融合多头自注意力机制的多特征分类预测

SCI一区 | Matlab实现ST-CNN-MATT基于S变换时频图和卷积网络融合多头自注意力机制的故障多特征分类预测 目录 SCI一区 | Matlab实现ST-CNN-MATT基于S变换时频图和卷积网络融合多头自注意力机制的故障多特征分类预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍…

论文阅读:Ground-Fusion: A Low-cost Ground SLAM System Robust to Corner Cases

前言 最近看到一篇ICRA2024上的新文章&#xff0c;是关于多传感器融合SLAM的&#xff0c;好像使用了最近几年文章中较火的轮式里程计。感觉这篇文章成果不错&#xff0c;代码和数据集都是开源的&#xff0c;今天仔细读并且翻译一下&#xff0c;理解创新点、感悟研究方向、指导…

【杂谈】还能这么骗Github开源者?

起因 StarkNet给Github前5000的账户空投了一波STRK代币,一般有资格获得空投的开发者&#xff0c;大概能获得 110个 STRK 代币&#xff0c;按目前价格计算大概 1500人民币左右。 什么是有资格的开发者呢&#xff1f;按 Starknet要求&#xff0c;如果你给在 GitHub上排名前 5000…

【精选】网络安全大厂面试题 2.0

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

基于SSM的废品买卖回收管理系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的废品买卖回收管理系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spri…

Spring Boot+ShardingSphere+MySQL实现分库分表:高效数据库扩展

在构建现代Web应用程序时&#xff0c;数据库的性能和可扩展性是至关重要的。当应用程序的数据量逐渐增加时&#xff0c;传统的单一数据库可能无法满足需求。分库分表是一种有效的数据库水平扩展方法&#xff0c;可以显著提高数据库性能并实现负载均衡。 什么是分库分表 分库分…

Vue+SpringBoot打造开放实验室管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实验管理模块2.4 实验设备模块2.5 实验订单模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示五、样例代码5.1 查询实验室设备5.2 实验放号5.3 实验预定 六、免责说明 一、摘…

数据库-数据库设计-社交关系

佛 每有一个新方案&#xff0c;就要考虑有什么影响增删改查可扩展性 MySQL 根据ER图设计表 create table follow(id bigint unsigned not null auto_increment comment 主键,gmt_create datetime null default current_timestamp,gmt_modified null default current_timest…

hive表中导入数据 多种方法详细说明

文章中对hive表中导入数据 方法目录 方式一&#xff1a;通过load方式加载数据 方式二&#xff1a;直接向分区表中插入数据 方式三&#xff1a;查询语句中创建表并加载数据&#xff08;as select&#xff09; 方式四&#xff1a;创建表时通过location指定加载数据路径 1. 创建表…

真值表,主析取范式,主合取范式,栈,哈希表

利用栈对表达式求值 根据运算符的各运算符的优先顺序&#xff0c;确定入栈操作 if(compare(s2.top(),s[i])-1)栈内的优先级小&#xff0c;栈外的运算符入栈if(compare(s2.top(),s[i])0)栈内的优先级与栈外的优先级相同&#xff0c;栈内运算符出栈if(compare(s2.top(),s[i]1)栈…

人工智能机器视觉、大数据与向量数据库的交融之路

文章目录 人工智能机器视觉、大数据与向量数据库的交融之路引言计算机视觉发展现状与趋势技术演进历程回顾当前的主要发展方向 大数据与计算机视觉的相互关系数据驱动下的CV技术进步向量数据库在图像检索与分析中的作用 具体应用案例剖析如何利用大数据和向量数据库解决CV难题代…

设计模式-创建型模式-建造者模式

建造者模式&#xff08;Builder Pattern&#xff09;&#xff1a;将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。 建造者模式一步一步地创建一个复杂的对象&#xff0c;它允许用户只通过指定复杂对象…

LeetCode 1393.股票的资本损益

Stocks 表&#xff1a; ---------------------- | Column Name | Type | ---------------------- | stock_name | varchar | | operation | enum | | operation_day | int | | price | int | ---------------------- (stock_name, day) 是这张表的主键(具有唯一值的列的组合) …

windows 中, bash: conda: command not found(已解决)

git bash 中运行conda命令&#xff0c;出现这种错误&#xff0c;原因是你没有在git bash中 配置conda&#xff0c;导致git bash无法找到conda 那就配置一下&#xff0c;找到你的conda的安装位置下的bash.sh文件&#xff0c;一般在安装位置&#xff08;我的安装在C盘的自定义路径…