0. 内存分区

  计算机中的内存在用于编程时,被人为的进行了分区(Segment),分为:

  -“栈区”(Stack)

  -“堆区”(Heap)

  -全局区(静态 区,Static)

  -文字常量区和程序代码区

  在前面的课程中,我们主要直接涉及到的是栈区的内存,在你的程序中,函数的参数值,局部变量的值等都被存在 了“栈区”,这部分的内存,是由系统来帮助你来管理的,没有特殊情况的时候,你是不需要对其进行特别处理的。计算机中内存的分配如下图。

  

  而针对堆区的内存,一般由程序员进行分配和释放, 使用堆内存的原因一般是

  -“栈上内存比较小,不够用”

  -“系统管理内存的方式死板,不方便用”

  对于堆上的内存,被程序员手动分配后,若程序员 不释放就可能会出现“内存泄漏”。很多企业级的应用,都因为内存泄漏而在“正常”运转很长时间后,轰然“坍塌”。在后面的入门课程中,我们会简单的对这块 的知识进行介绍。

  全局区、文字常量区和程序代码区在我们入门阶段,暂时还可以不去过多理解(甚至看不懂也无妨),只需要知道他们的大致作用即可——全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 程序结束后由系统释放;文字常量区是用于储存常量字符串的, 程序结束后由系统释放;程序代码区用于存放函数体的二进制代码。

1. C++类的写法

C++类的两大经典写法:

Class without pointer member(s)  比如 课程中定义的 Complex 类。

and  

Class with pointer member(s)  比如 系统中的 string 类。

2. C++正规、大气的写法

2.1 使用“防卫式声明”

#ifndef _COMPLEX_
#define _COMPLEX_ class Complex
{
  //some declaration
} #endif

2.2 使用“构造函数初始值列表”

尽量在声明构造函数时使用“构造函数初始值列表”,因为这样在变量的声明阶段就赋予了值,有助于提高效率。

2.3 使用“const”

为了代码在以后被其他程序员复用中,在“顶层”能使用const关键字限定行为,所以我们在做“底层”工作时,要充分考虑到使用const限定函数行为。

同时注意C++语法的“顶层const”原则。

另外,在类body的定义中,也尽量使用“const”语法。

2.4 使用”引用“

尽量考虑使用“引用”这一语法。因为在传递的过程中开销比较小—— 一个4字节的指针。

但是引用也有一些缺点,比如引用的不安全性——引用的母体的值可能会通过子体被修改。所以我们可以在引用的地方考虑使用const。

3. inline

函数若在 class body 内完成定义,该函数便自动成为 inline “候选人”。

太复杂的函数无法成为“真正的” inline function,即便是用 inline 声明。

4. 参数传递

两种方式:

pass by value  程序栈内数据直接拷贝,开销比较大。

and  

pass by reference (to const)  “引用”语法的底层实现是指针,所以传4字节的指针开销比较小。形式美观。

inline complex& complex::operator += (const complex& r)
{
return __doapl (this, r);
}

6. 友元

6.1 提高性能

在一些情况下,为了提高性能,请尽量通过友元实现数据存取。

因为通过使用友元语法,可以省略掉一步多余的——通过类共有方法实现存取类私有数据——操作,因此可以提高性能。但也破坏了封装。

6.2 特性

同一类的各个对象互为友元。例如下面代码:

class complex
{
public:
Complex (double r = , double i = )
: re(r), im(i)
{ } int func(const complex& param)
{ return param.re + param.im; } private:
double re, im;
}; int main()
{
complex c1(, );
complex c2(); c2.func(c1);
}

7. “引用”的不适用场景

inline complex&
__doapl (complex* ths, const complex& r)
{
ths->re += r.re; //第一参数将会被改动
ths->im += r.im; //第二参数将不会被改动
return *ths;
}

因为 r 是一个引用,当函数执行完成,空间被回收以后,引用这一实体将不存在。

8. 如何实现C++高性能

侯杰认为,好的C++程序应该具备

  • 数据尽可能放在 private 区
  • 参数尽可能使用 reference 传递
  • 返回值尽可能使用 reference 传递
  • class body 中尽可能使用 const 语法
  • 尽可能使用 构造函数初始值列表

9. 运算符重载

9.1 成员函数

作为类的成员函数,运算符重载要写成如下的形式。“+=”运算符右边的操作数作为函数的参数被传递;“+=”运算符左边的操作数作为类内部的 this 指针。

inline complex& complex::operator += (const complex& r)
{
return __doapl (this, r);
}

为了便于理解,可以写成如下形式(语法错误,但是便于理解)。

// 语法有错误,但是便于理解。注意第一个参数:this
inline complex& complex::operator += (this, const complex& r)
{
return __doapl (this, r);
}

9.2 非成员函数

作为非成员函数的重载,函数定义时operator关键字前面不应该有 “类名::”限定符。代码如下:

inline complex operator + (const complex& x, const complex& y)
{
return complex (real (x) + real (y), imag (x) + imag (y));
}

其中,return complex(......)表示声明了一个临时对象,并将其直接返回。这样的写法——返回临时对象——在STL中很常见。

如果作为“成员函数”的重载,代码如下:

inline complex& complex::operator += (const complex& r)
{
return __doapl (this, r);
}

10. return by reference 语法分析

传递者无需知道接收者是从reference形式接收。

11. STL :: complex类中的优良写法

  • initialization list (构造函数初始化列表)
  • 函数 const
  • 参数传递尽量 pass by reference
  • 函数返回值尽量 return by reference
  • 数据声明在 private

12. 关于引用的讨论

引用传递的底层实现是一根4字节的指针,所以开销相比较而言较小。

但是对于“基本内置类型”比如 bool, double, char[4]以内, int直接传递其本身与传递引用效率是一样的,这就需要程序员根据编程规范自己取舍。

13. 成员函数声明时const

在声明成员函数时加上const关键字,如代码所示:

class complex
{
public:
double real () const { return re; }
};

表示该函数不被允许修改类中的成员变量。

14. C++组成部分

C++由两部分组成:C++语言本身 和 C++标准库。

15. STL complex类代码区域划分

主要分成三部分:前置声明、类声明、类定义。

#ifndef __COMPLEX__
#define __COMPLEX__ /* 0 前置声明 */
#include <cmath> class ostream;
class complex; complex& __doapl ( complex* ths, const complex& );
/* end 0 前置声明 */ /* 1 类声明 */
class complex
{ };
/* end 1 类声明 */ /* 2 类定义 */
complex::function....
/* end 2 类定义 */ #endif // __COMPLEX__

16. 附录

complex 类代码如下:

#ifndef __MYCOMPLEX__
#define __MYCOMPLEX__ class complex;
complex&
__doapl (complex* ths, const complex& r);
complex&
__doami (complex* ths, const complex& r);
complex&
__doaml (complex* ths, const complex& r); class complex
{
public:
complex (double r = , double i = ): re (r), im (i) { }
complex& operator += (const complex&);
complex& operator -= (const complex&);
complex& operator *= (const complex&);
complex& operator /= (const complex&);
double real () const { return re; }
double imag () const { return im; }
private:
double re, im; friend complex& __doapl (complex *, const complex&);
friend complex& __doami (complex *, const complex&);
friend complex& __doaml (complex *, const complex&);
}; inline complex&
__doapl (complex* ths, const complex& r)
{
ths->re += r.re;
ths->im += r.im;
return *ths;
} inline complex&
complex::operator += (const complex& r)
{
return __doapl (this, r);
} inline complex&
__doami (complex* ths, const complex& r)
{
ths->re -= r.re;
ths->im -= r.im;
return *ths;
} inline complex&
complex::operator -= (const complex& r)
{
return __doami (this, r);
} inline complex&
__doaml (complex* ths, const complex& r)
{
double f = ths->re * r.re - ths->im * r.im;
ths->im = ths->re * r.im + ths->im * r.re;
ths->re = f;
return *ths;
} inline complex&
complex::operator *= (const complex& r)
{
return __doaml (this, r);
} inline double
imag (const complex& x)
{
return x.imag ();
} inline double
real (const complex& x)
{
return x.real ();
} inline complex
operator + (const complex& x, const complex& y)
{
return complex (real (x) + real (y), imag (x) + imag (y));
} inline complex
operator + (const complex& x, double y)
{
return complex (real (x) + y, imag (x));
} inline complex
operator + (double x, const complex& y)
{
return complex (x + real (y), imag (y));
} inline complex
operator - (const complex& x, const complex& y)
{
return complex (real (x) - real (y), imag (x) - imag (y));
} inline complex
operator - (const complex& x, double y)
{
return complex (real (x) - y, imag (x));
} inline complex
operator - (double x, const complex& y)
{
return complex (x - real (y), - imag (y));
} inline complex
operator * (const complex& x, const complex& y)
{
return complex (real (x) * real (y) - imag (x) * imag (y),
real (x) * imag (y) + imag (x) * real (y));
} inline complex
operator * (const complex& x, double y)
{
return complex (real (x) * y, imag (x) * y);
} inline complex
operator * (double x, const complex& y)
{
return complex (x * real (y), x * imag (y));
} complex
operator / (const complex& x, double y)
{
return complex (real (x) / y, imag (x) / y);
} inline complex
operator + (const complex& x)
{
return x;
} inline complex
operator - (const complex& x)
{
return complex (-real (x), -imag (x));
} inline bool
operator == (const complex& x, const complex& y)
{
return real (x) == real (y) && imag (x) == imag (y);
} inline bool
operator == (const complex& x, double y)
{
return real (x) == y && imag (x) == ;
} inline bool
operator == (double x, const complex& y)
{
return x == real (y) && imag (y) == ;
} inline bool
operator != (const complex& x, const complex& y)
{
return real (x) != real (y) || imag (x) != imag (y);
} inline bool
operator != (const complex& x, double y)
{
return real (x) != y || imag (x) != ;
} inline bool
operator != (double x, const complex& y)
{
return x != real (y) || imag (y) != ;
} #include <cmath> inline complex
polar (double r, double t)
{
return complex (r * cos (t), r * sin (t));
} inline complex
conj (const complex& x)
{
return complex (real (x), -imag (x));
} inline double
norm (const complex& x)
{
return real (x) * real (x) + imag (x) * imag (x);
} #endif //__MYCOMPLEX__

C++面向对象高级开发课程(第一周)的更多相关文章

  1. C++面向对象高级开发课程(第三周)

    一,类与类之间的关系:继承(Inheritance).复合(Composition).委托(Delegation). 二,复合:表示 is-a ,该设计思想可以参照C语言的 struct . 1. 例 ...

  2. C++面向对象高级开发课程(第二周)

    1. 类中含有指针—— class with pointer member(s) ——的情况经常发生,典型的有:string 类. 2. STL中的 string 类太复杂,copy on write ...

  3. j2ee高级开发技术课程第一周

    一.课程目标 这学期开始了J2EE高级开发技术这门课,在此之前我学习了javaSE,为这门课的学习打下了一定的基础.到这学期的结束我希望我能熟悉javaee,能开发企业级应用,对开发轻量级企业应用的主 ...

  4. 扎西平措 201571030332《面向对象程序设计 Java 》第一周学习总结

    <面向对象程序设计(java)>第一周学习总结 正文开头: 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 ...

  5. 201871010124 王生涛《面向对象程序设计JAVA》第一周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://edu.cnblogs.com/campus/xbsf/ ...

  6. 201871010132-张潇潇《面向对象程序设计(java)》第一周学习总结

    面向对象程序设计(Java) 博文正文开头 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cn ...

  7. Chromium浏览器高级开发系列第一篇:如何获取最新chromium源码

    背景:     最近摊上一个事儿,领导非要让写一篇技术文章,思来想去,自己接触chrome浏览器时间也不短了,干脆就总结一下吧.于是乎,本文顺理成章.由于有些细节必需描述清楚,所以这次先讲如何拿到ch ...

  8. 《Linux内核分析》课程第一周学习总结

    姓名:何伟钦 学号:20135223 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...

  9. 网易Java高级开发课程随笔

    java学习也有6个月之久,记录下课程相关知识点,目前我还没有掌握,so仅作技术点记录 鉴于在.NET上我封装了一套开发框架,虽去年按.NET封装的思路自己也弄了个java开发框架,还是感觉对java ...

随机推荐

  1. Linux系统下便捷使用中国知网的方式

    https://blog.csdn.net/mowangajimide/article/details/54144379

  2. 使用Pangolon在同一副图中,画出两个轨迹,比较误差

    使用 code/ground-truth.txt 和 code/estimate.txt 两条轨迹.请你根据上面公式,实现 RMSE的计算代码,给出最后的 RMSE 结果.作为验算,参考答案为:2.2 ...

  3. R数据可视化手册学习——条形图

    1. 绘制简单条形图 # 使用ggplot2和gcookbook library(ggplot2); library(gcookbook) g <- ggplot(data = pg_mean, ...

  4. .Net微服务架构之运行日志分析系统

    一.引言 .Net技术栈目前还没有像spring cloud相对完整一整微服务架构栈,随着业务发展系统架构演进,自行构建.Net技术体系的微服务架构,配套相关核心组件.因平台基于微服务架构方式研发,每 ...

  5. ssh各种姿势---ssh-keygen 生成ssh公钥和私钥

    利用ssh-keygen -t rsa可以生成ssh公钥和私钥,实现免输密码的ssh登陆     ssh-keygen -l -f /etc/ssh_host_rsa_key   ssh-keygen ...

  6. Python 目录【持续更新中】

    Python 基础 字符编码 数据类型 文件处理 流程控制 练习题 函数,递归 匿名函数.内置函数 装饰器变形记 函数装饰器 递归 二分法 迭代器和生成器 协程函数 列表表达式 生成器表达式 异常处理 ...

  7. inter x86 emulator accelerator(HAXM installer) not compatible with windows

    在SDK manager中遇到如下错误:这将导致AVD后期运行和启动方面的问题. 解决办法: 在如下的网址里面下载haxm-windows_v6_2_0这个文件的压缩包,自己手动安装即可.网站如下:点 ...

  8. python类内部调用自己的成员函数必须加self

    class A: def a(self): print("hello world") def b(self): return self.a() 上面的self.a()中self是不 ...

  9. Civil and Evil Engineer(普林姆)

    http://acm.sdut.edu.cn:8080/vjudge/contest/view.action?cid=198#problem/E 水题一道,题意就是让求一遍最小生成树与最大生成树,但我 ...

  10. PAT Spell It Right [非常简单]

    1005 Spell It Right (20)(20 分) Given a non-negative integer N, your task is to compute the sum of al ...