C/C++非专家级编程

0.关于定义,那是只有编译器才喜欢的语法——Peter Van Der Linden 《C专家编程》

需要注意的是指针运算符*是右结合的,你最好从右往左读

const   int   *  a;   //a是一个指针,指向const  int

int   const   *  a;   //同上

int    * const  a;   //a是一个常指针,指向int

  int   *   const   *  a;  //a是一个指针, 指向一个int  *   const ——指向int的常指针

// ** a 可变, * a不可变,a可变

 
int  value  =   10 ;

int   *   const   *  a;

int   *   const  b1  =   & value;

int   *   const  b2  =   & value;

 
a  =   & b1;  //  ok

* a  =  b1;  //  failed

** a  =   6 ;  //  ok

当个编译器..面对一个无比恶心的声明:

1.从左向右找到第一个标识符,表示“标识符是”

2.看标识符右边下一个符号,左方括号表示“是数组”、左圆括号表示“是函数”

3.看标识符左边下一个符号,*/const/volatile 表示“是指针(const的或volatile)”注意指针从右往左读是右结合的

4.如果左边是一个左括号,把已经处理的生命组合在一起,知道遇见对应的右括号,然后从第二步重新开始

test:

一个取自Telnet的声明:

char* const* (*next)();

next是一个指向函数的指针,这个函数参数是void,返回值是一个指针,指向一个类型为char的常指针

ANSI C中signal()的声明

void (*signal(int sig, void(*func)(int)))(int);

signal是一个函数,参数是int和void(*func)(int)——一个指向函数的指针,返回值void参数int。

signal的返回值是一个指向函数的指针,该函数返回void参数int

参考《C专家编程》第三章

1.指针和数组不是一回事

C/C++中指针和数组不是一回事,只有一种情况下除外——被当作函数形参的时候。【确切的说,访问指针会比访问数组多一次访存】。因为指针是一个变量,变量的内容是一个地址。

访问指针过程:在【符号表】找到指针变量地址,根据地址访问内存,从内存中取出地址再加上偏移量,再访问目标地址。(三次)

访问数组过程:在【符号表】找到数组起始地址,加上偏移量,访问目标地址。(二次)

如果一个数组被声明为:

extern char *p;

但原先定义却是:

char p[10];

当用p[i]这种形式提取这个【声明】的内容时,实际上得到的是一个字符,但是按照上面的方法,编译器却把它当作一个指针,把ASCII字符解释成地址显然是牛头不对马嘴。(《C专家编程》P86)

2. 注意继承中默认构造函数的行为,一般你需要在初始化列表中指定一个base class
C++中,继承自一个类的派生类会自动调用父类的默认构造函数,如果父类无默认构造函数,会导致编译失败:no appropriate default constructor available. 此时必须由子类通过初始化列表显式指定一个构造函数,如:

Child::Child(int pa):Father(pa, 11)

{

return ;

}

3.引用是没有语法指针的指针,又称为别名,可以用作对象的另一个名字。只能初始化一次

4.dynamic_cast 一般用于父类向子类的转换,此时父类必须要有虚函数,否则编译器会报错。

dynamic_cast一般是用来检测一个基类的指针指向的是不是一个特定的子类型的对象 ,它被用于安全地沿着类的继承关系向下进行类型转换。这就是说,你能用dynamic_cast把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用,而且你能知道转换是否成功。

—— MECPP

dynamic_cast 操作符是RTTI的一部分,它支持在运行时刻查询一个多态指针或引用所指向对象的实际类型

dynamic_cast 就是Java中常用的向下转型. 失败的对引用转换将抛出std::bad_cast异常 此类型被包含在 头文件<typeinfo>

static_cast 一般用于编译器隐式的类型转换,不能从表达式中去除const属性

const_cast  用于转换掉表达式中const或者volitileness属性(前提是最本质的属性是非const)

5.namespace 使用

// primer.h

namespace  cplusplus_primer  ... {

       class Matrix ...{/**//* ... */};

       extern Matrix operator+(const Matrix &m1, const Matrix &m2);

       extern void inverse(Matrix &);

       extern bool error_state;

}

// primer.c

namespace  cplusplus_primer  ... {

       void inverse(Matrix &) ...{

 

       }

 

       Matrix operator+ (const Matrix &m1, const Matrix &m2) ...{

              /**//*

              ....

              */

       }

}

6. inline 成员函数必须在每个调用它的文本文件中被定义,所以没有在类体定义的内联成员函数必须被放在类定义出现的头文件当中。此外inline是一种请求而不是必须,有可能编译器会拒绝inline一个成员函数。

7. C++异常抛出的是任意类型,对应捕捉的类型相同即可,传递的最好是引用以提高效率 。

8. C++中的多态和Java类似,主要指基类的【指针】或【引用】可以指向其任意派生类的能力。成员函数动态绑定的基础是它被声明为virtual,这样多态函数才会在执行器进行类型检查,否则将会直接调用父类的成员函数。

9. 类设计准则

类层次结构的公有接口应该提供哪些操作

这些操作之中,哪些应该被声明为虚拟的(以支持动态绑定)

单个的派生类需要哪些其他的操作

在抽象类中应该声明哪些数据成员

单个的派生类要求哪些数据成员

被所有子类共享的操作不必声明为虚拟函数,子类需执行特有操作的使用虚拟函数提供公共接口和动态绑定,每个派生类提供自己的实现。

继承而来的派生类虚拟函数实例,不再需要(但也可以)指定关键字virtual。编译器会比较函数的原型,从而识别出这个实例。

基类中的虚拟函数可以选择不实现,称之为纯虚拟函数。它被用作类层次结构公有结构中的一个占位符。它也不希望在程序中被调用,而每个后续的派生类都将提供一个实际的实例。

例如:

virtual void eval()=0;

这也意味着此基类不可被实例化,任何实例化此类的操作都会导致编译器报错中止:

base class is abstract:see declaration of base class

10. 继承得到的成员函数没有构成派生类中的重载函数。

C++初学者常见的一个误解是,希望基类和派生类的成员函数构成一个重载函数集,但是实际上这样理解是错误的。见<<C++ Primer 3rd>> p738

如果我们真的想提供一个重载函数集,可以使用一个inline函数套起来,里面手动调用基类的相应函数。或者在派生类函数定义区使用using指示符,引入所有基类相应的成员函数作为重载函数。

11. 构造函数的调用顺序如下:

1、基类构造函数。调用顺序是基类在派生表中的顺序 传递参数可以使用初始化列表指定需调用的基类构造函数。

2、成员类对象构造函数。调用顺序是对象在类中被声明的顺序,而不是他们出现在成员初始化列表中的顺序。

3、派生类构造函数。作为一般的规则,派生类构造函数应该不能直接向一个基类数据成员赋值,而是把值传递给适当的基类构造函数。否则,两个类的实现将编程紧耦合的,将更加难于正确的修改和实现基类的实现,而且这会调用拷贝构造函数,造成效率上的底下。(基类设计者的责任是提供一组适当的基类构造函数)

基类构造函数可以声明为protected以保证基类不会被实例化。

构造函数不会被继承,因为这样太容易引入“未初始化派生类成员”错误。正确的做法是通过初始化成员列表向基类传递构造函数参数(指定使用哪个构造函数,默认情况是无参构造函数)。

而且,派生类构造函数智能合法地调用其直接基类的构造函数。

12. 友元声明不能被继承。我觉得最好的情况是,干脆不要用友元,学学Java的做法。

13. 虚拟函数只在使用指针和引用时才会如预期般的起作用。只有通过基类指针或引用间接指向派生子类型时,多态性才会起作用。

14. 作为一般的规则,应将类层次结构的根基类(声明了一个或多个虚拟函数)的析构函数声明为虚拟的。但是,不像基类的构造函数,一般的基类的析构函数不应该是protected

15. C++中clone的用法。

对于要求“派生类成员函数的返回类型必须与其基类实例的返回类型完全匹配”有一个例外就是支持这种情况。如果虚拟函数的基类实例返回的是一个类类型(或指向类类型的指针或引用),则派生类实例可以返回一个“从基类实例返回的类公有派生出来”的类。《c++ primer 3rd》 P769

16. private继承是一种特殊的继承。

private继承,基类所有的公有接口在派生类中会成为private,一个private基类反映一种“并非基于子类型关系”的继承形式,并不是一种is-a关系,是一种has-a关系。

但是到底是用组合还是private继承来实现has-a关系有一定的准则(《C++ primer 3rd》P803)。在大多数情况下,我认为应该使用组合,这点也是Java的实现。

17. 多重继承可能导致一个基类在派生层次中多次出现,最典型的,它的构造函数将被调用两次,所以在这种情况下,继承该基类应该使用虚拟继承。《C++ primer 3rd》 P813

18. 使用RTTI的前提是基类中定义了虚函数.

C/C++非专家级编程相关推荐

  1. 软件工程 / 为什么基于接口而非实现编程?

    基于接口而非实现编程(基于抽象而非实现编程)的目的是解耦. 这里面接口的含义可以理解为 dll 或者 so 文件对应的头文件中提供的函数列表,或者理解为C++中的抽象类. 该原则可以将接口和实现分离, ...

  2. Java异步非阻塞编程的几种方式

    简介: Java异步非阻塞编程的几种方式 一. 从一个同步的Http调用说起 一个很简单的业务逻辑,其他后端服务提供了一个接口,我们需要通过接口调用,获取到响应的数据. 逆地理接口:通过经纬度获取这个 ...

  3. Java NIO 非阻塞网络编程快速入门

    NIO 非阻塞网络编程快速入门 案例: 编写一个 NIO 入门案例,实现服务器端和客户端之间的数据简单通讯(非阻塞) 目的:理解 NIO 非阻塞网络编程机制 import java.net.InetS ...

  4. 为什么基于接口而非实现编程?

    如何解读原则中的"接口"二字? "基于接口而非实现编程"这条原则的英文描述是:"Program to an interface, not an imp ...

  5. 高并发网络编程之NIO非阻塞网络编程

    文章目录 NIO非阻塞网络编程 Buffer缓冲区 Buffer工作原理: ByteBuffer内存类型 Channel通道 SocketChannel ServerSocketChannel Sel ...

  6. 001-006 Rust死灵书笔记之非安全编程与数据布局

    介绍 本系列笔记是我录制Rust高级编程的系列笔记,在对第一二章录制时,采用的是xmind梳理知识点的形式,因此将第一二章的知识点集中放在此进行展示. 本系列录制的视频主要放在B站上Rust死灵书学习 ...

  7. 阻塞式和非阻塞式udp传输_NIO非阻塞网络编程三大核心理念

    本次开始NIO网络编程,之前已经说过BIO,对于阻塞IO里面的问题一定有了清晰的认识,在JDK1.4版本后,提供了新的JAVA IO操作非阻塞API,用意替换JAVA IO 和JAVA NetWork ...

  8. 非阻塞网络编程详解------IO模型

    1.前言 随着互联网的发展,面对海量用户高并发业务,传统的阻塞式的服务端架构模式已经无能为力.本文(和下篇<高性能网络编程(六):一文读懂高性能网络编程中的线程模型>)旨在为大家提供有用的 ...

  9. 开课吧 Python专家级编程:机制与实操

    现在互联网上广为流传的[18届互联网校招薪酬表],震惊了还在敲代码的小编我,给你们看看这张高薪表 需要联系QQ  2370513896 可以看到上图50%以上的高薪都是AI相关的岗位,不管是具备了算法 ...

最新文章

  1. python基础-第九篇-9.3线程池
  2. 存储过程DataGrid分页及注意点
  3. 几个经常需要自定义的View总结
  4. 【解题报告】Leecode 384. 打乱数组——Leecode每日一题系列
  5. python入门系列:深入Python的set和dict
  6. 前端学习(2576):选择何种方式的路由和底层原理
  7. 【今日CV 计算机视觉论文速览 第127期】Fri, 7 Jun 2019
  8. 爱奇艺的测试工程师笔试题
  9. sdut1283Five in a Row, Again
  10. 全国计算机office二级选择题,全国计算机二级msoffice选择题汇总含答案
  11. 软件_搭建rtmp视频推送环境,腾讯云,ubuntu16
  12. Spark Streaming 源码详解
  13. interview material
  14. 计算机屏幕上的显示记录,什么样的桌面日历便笺既可以显示日期又可以提醒我所记录的时间表...
  15. SAP SHIFT语法注意
  16. 芯片工程师成长之路_从入门到精通,电子硬件工程师的成长之路
  17. assignin与evalin用法理解
  18. DNSPod十问袁志远:智慧园区,被严重低估的To B赛道?
  19. AD2020库安装及查找库
  20. opencv h264压缩视频

热门文章

  1. PostgreSQL使用PostGIS插件,存储GIS数据
  2. Nodejs-Express, Koa, Hapi三个框架应如何选择
  3. 电脑上的设备驱动程序是什么(通俗解释)
  4. 三,天猫精灵SDK驱动开发板LED
  5. php redis中set、setex、setnx、getSet的区别
  6. 关于【商品计量单位以及这些计量单位换算】的设计
  7. ubuntu18.04 安装惠普打印机驱动GUI界面
  8. 刀片服务器在哪看cpu型号,了解认识刀片服务器
  9. 【Flutter】使用高德地图实现地图选点以及地图搜索
  10. git 错误:GnuTLS recv error (-54): Error in the pull function