前言

众所周知,封装、继承和多态是面向对象编程的三大特性。C++作为一门面向对象的编程语言,自然支持了这些特性,但C++是如何实现这些特性的呢?今天先说下我理解的封装。

封装

通常我们会把下面的行为也叫封装,但面向对象的封装并不只是把函数或类型包裹在一起,更重要的是给这些函数或类型设置访问权限

  • 将一堆类型变量用一个结构体包裹起来,对外只有一个结构体名
  • 将一堆过程用一个函数包裹起来,对外只有一个函数名

C++提供了三种权限

  • public:任何类都能可访问
  • protected:只有本类或本类的派生类能访问
  • private:只有本类能访问

    类指classstruct,并不单指classclassstruct只有默认访问权限的区别
    友元类和友元函数能访问该类的任何东西

访问权限只在编译阶段检查,而且检查的依据只是当前的类声明,举个例子来说明

  • 执行g++ student.cpp -fPIC -shared -o liba.so将以下代码编译为动态库,提供给其他人使用。
// student.h
class Student
{
public:
    Student();
private:
    int age;
};

// student.cpp
#include "student.h"
Student::Student()
{
    age = 10;
}
  • 篡改student.h,将所有成员变量的访问权限都设为public
class Student
{
public:
    Student();
    int age;
};
  • g++ main.cpp -L./ -la编译没有报错。——从此就可以看出“权限检查的依据只是当前的类声明”
// main.cpp
#include "student.h"
int main()
{
    Student s;
    s.age = 40; // 肆意变更自己的年纪
    return 0;
}

当然可以采用如下的方式来隐藏内部成员变量细节,这样即使调用者修改了类声明里的访问权限,也不知道为了来达到自己的目的该如何修改。

// student.h
class Student
{
public:
    Student();
private:
    struct Internal;
    Internal* in;
};

此外,这还带来一个好处就是内部成员变量的修改,调用者完全无感知,不需要更新头文件了(我想这才是使用这种方式的主要原因)。当然这仍然无法阻止别人猜测出数据结构后,直接使用成员变量地址去读写。个人觉得只有提供给第三方或第二方的类才需要使用这种方式(内部还是可以信任的)。如果所有类都这样实现的话,可能就会导致内存碎片了。

结语

我觉得封装最大的意义还是在于让调用者不要关注自己无权访问的内容(忽略细节),只需要基于自己可访问的部分(基于接口)去实现业务。C是一门面向过程的语言,它是没有访问权限这一说的,调用者无法知道哪些是自己无权访问的,编译器也无法提醒越权访问的错误,C++则提供了这种编程约束

C++系列总结——封装的更多相关文章

  1. 架构漫谈系列(2) 封装(Encapsulation)

    这是这个系列的第二篇.在第二篇里,我决定讲一讲封装. 程序的不同部分应该用封装去互相隔离,模块之间应该不应该产生很随意的关联. 可能有的人觉得不解,又或觉得是有道理的废话,不急,先一步一步来. 我们先 ...

  2. 3-STM32带你入坑系列(自己封装点亮一个灯的库--Keil)

    2-STM32带你入坑系列(点亮一个灯--Keil) 首先建一个stm32f103x.h的文件,然后 #include "stm32f103x.h" 还记得上一节 现在呢就是做一个 ...

  3. jQuery组件系列:封装标签页(Tabs)

    我自己封装的组件,你也行,静态链接地址 http://www.cnblogs.com/leee/p/5190489.html 声明.最好,先把代码拷过去运行一下,其实特别丑~再往下看 我没优化,因为我 ...

  4. <数据结构系列1>封装自己的数组——手写动态泛型数组(简化版ArrayList)

    哈哈,距离上一次写博客已经快过去半个月了,这这这,好像有点慢啊,话不多说,开始我们的手写动态泛型数组 首先是我们自己写一个自己的动态数组类,代码如下所示: public class Array< ...

  5. javascript设计模式系列二-封装

    JavaScript封装: var Book = function (id, name, price) { this.id = id, this.name = name, this.price = p ...

  6. JS组件系列——自己封装一个上传文件组件

    页面调用: $('#fileUpload').cemsUpload({ errorEmpty:'<s:text name="cupgrade.view.tip.upload.file. ...

  7. 测试平台系列(80) 封装Redis客户端

    大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 回顾 上一节我们编写了Redis ...

  8. openssl之EVP系列之1---算法封装

    openssl之EVP系列之1---算法封装     ---依据openssl doc/crypto/EVP.pod翻译和自己的理解写成     (作者:DragonKing, Mail: wzhah ...

  9. 封装的多功能多效果的RecyclerView

    开源界有一句很有名的话叫"不要重复发明轮子",当然,我今天的观点不是要反驳这句话,轮子理论给我们的开发带来了极大的便利,.但我想说的是,既要会用轮子,也要知道轮子怎么造,必要的时候 ...

随机推荐

  1. RabbitMQ和Kafka到底怎么选?

    前言 开源社区有好多优秀的队列中间件,比如RabbitMQ和Kafka,每个队列都貌似有其特性,在进行工程选择时,往往眼花缭乱,不知所措.对于RabbitMQ和Kafka,到底应该选哪个? Rabbi ...

  2. IE不兼容ES6箭头函数的解决方法(在浏览器中使用)

    polyfill.js下载方法: npm install babel-polyfill --save 页面中引用"polyfill.js" 和 "browser.min. ...

  3. Spark学习之RDD编程总结

    Spark 对数据的核心抽象——弹性分布式数据集(Resilient Distributed Dataset,简称 RDD).RDD 其实就是分布式的元素集合.在 Spark 中,对数据的所有操作不外 ...

  4. Docker入门学习

    Python爬虫 最近断断续续的写了几篇Python的学习心得,由于有开发经验的同学来说上手还是比较容易,而且Python提供了强大的第三方库,做一个小的示例程序还是比较简单,这不我之前就是针对Pyt ...

  5. 学习 JavaScript (七) 内存问题

    内存问题是 JavaScript 比较底层的东西,依葫芦画瓢学会了怎么使用变量,但是对于内存的概念依然模糊,今天让我们一起来了解一下内存在这门语言是怎么样的存在. 内存在不同类型的数值面前表现有很大的 ...

  6. Windows中使用Mysql-Proxy实现Mysql读写分离

    1.简介 读写分离:当业务量上来时,往往一台单机的mysql数据库不能满足性能需求,这时候就需要配置主从库读写分离来解决性能瓶颈.简单的来说,就是原先一台数据库既读又写,现在改成一台写和1台以上读. ...

  7. c#发送邮件,可发送多个附件

    1:创建SendMail类 2:调用方法 SendMail send = new SendMail("123456@qq.com", "123456@163.com&qu ...

  8. PowerDesigner制作UMI图

    首先我们要下载一个PowerDesigner,自己上百度下载哈!嘻嘻!!! 我这个是汉化版的 然后点这个,再到空白的地方点一下就创建好了. 然后单击右边箭头然后双击 不管是制作的图还是代码生成的图都可 ...

  9. 14 ,CSS 文字与文本

    1.CSS 中长度与颜色 2.CSS 中的文字属性 3.CSS 中的文本属性 14.1 CSS 中长度与颜色 长度单位 说明 in 英寸 cm 公分 mm 公里 cm 以目前字体高度为单位 ex 以小 ...

  10. ArcGIS API for JavaScript 4.x 本地部署之IIS法

    [导读] 关于如何在默认网站(Default Web Site,物理地址C:\inetpub\wwwroot\)启动,已有很多博客详尽地写好了. 本篇在自建网站(本机)中配置http而非https的j ...