1 C++简介
OOP: Object Oriented Programming
面向对象: 是一种思想
procedural language: 过程式语言
1.1 class 设计
小代码 & 良好的 c++ 编程习惯
1 Object Based
基于对象: 单一 class
2种 经典 class 分类:
class with / without pointer members: String / Complex
2 Object Oriented
面向对象: 多个class, 主要考虑 class 间关系
继承 inheritance
组合 composition
委托 delegation
1.2 C++ 演化
new C -> C with class -> C++: 1983
C++98(1.0) -> C++11(2.0)
1.3 相比于 C, C++ 更注重 标准库
C: 主要关注 语言层面
C++: C++ 语言 & C++ 标准库
1.4 好书
1 语言部分
全世界最畅销的2本
<< C++ Primer >> C++ 第1个编译器作者
<< The C++ Programming Language >> C++之父 Bjarne Stroustrup
2 专家经验
<< Effective C++>>
3 标准库
<< The C++ Standard Liarbry >>
<< STL 源码剖析 >>
STL: Standard Template Library, 是 标准库的前身
2 class 声明
2.1 C++ 与 C: ptr 和 func 不同
C:
数据: 具有 类型/type (build-in, struct)
据 类型 create 出 Variables
函数: 处理 variables
C++:
wrap ptr 和 ( 处理 ptr 的 ) func, 形成 class
以 class 为 type create 出 objects
C++ 的 class 源于 C 的 struct, 又加入了新特性
ptr/对象 可能有 多份/多个, 处理对象的 `函数 只有1份`
2.2 C++ ptr 与 func
1 Complex
ptr: 实部 虚部
Functions:
2 String
ptr: ptr — 指向1个 字符串
functions: copy 等
2.3 C++ 代码
.h/hpp: 标准库
.h : class Declaration
.cpp: include<> + include " "
2.4 C++ / C: 输出
C++: 不需要 告诉编译器 要输出的变量 类型
//c++
int i = 5;
cout << i << endl;
//c
printf("%d\n", i);
2.5 头文件 & 防卫式声明
程序 中 第1次 include 头文件 时,
由于 未曾定义过 _COMPLEX_ 这个 name, 所以定义它;
然后进入 头文件 body.
第2次 include 头文件 时,
由于 已定义过 _COMPLEX_ , 所以 不会进入 头文件 body
// complex.h
#ifndef _COMPLEX_
#define _COMPLEX_
...
#endif
2.6 头文件布局
// A.h
#ifndef _A_
#define _A_
// (1) 前置声明
class B;
// (2) class 声明
class A
{
// class body 内 直接定义 的 函数
};
// (3) class body 外 定义 的 函数
A::function ...
#endif
3 构造函数
1 class 声明
class complex
{ // class body
friend complex& _doapl (complex*, const complex&);
public:
complex (double r = 0, double i = 0) // 1. default arg
: re (r), im (i) // 2. initialization list 初始化列表, 只有 ctor 享有这种语法
{ }
complex& operator+=(const complex&);
double real () const { return re; }
double imag () const { return im; }
private:
double re, im;
};
2 inline func
inline 好处: 非函数调用
函数 `建议` 编译器 把自己做成 inline(候选人) 的 2种情形:
(1) class body 内 定义 => `自动成为 inline 候选人`
(2) class body 外 explicitly 声明为 inline
3 ctor
可 overload
(1) 在 编译器 看来, 重载函数 不同名
(2) 二义性 -> 编译器 不知道 调哪个 -> 编译 error
complex (double r = 0, double i = 0)
: re (r), im (i) { }
complex () : re(0), im(0) {};
4 参数传递 与 返回值
1 ctor 放 private => class 称为 Singleton 单例
(1) class 只在 内部 构造 1份 自己的 static obj, 供 外部 使用
(2) 不允许外界 创建 object
class A
{
public:
static A& getInstance();
setup(){ /* */ }
private:
A();
A(const A& rhs);
};
A& A::getInstance()
{
static A a;
return a;
}
// 调用 A::getInstance().setup();
2 const member func: 不改 mem ptr
const obj 调 non-const mem func => compiler 报错
`const 对象: 告诉 编译器, 不能改 mem ptr`
`non-const mem func: 允许改 mem ptr`
class
{
public:
double complex::real () const { return re; }
};
3 参数传递: pass by value vs. pass by reference (to const)
能传引用 就 传引用
(1) 引用
[1] 本质上 也是 指针, 传引用 像 传指针 一样快
[2] 必须 绑定到 已有对象
(2) 指针: 可以是 动态内存的地址
=> 此时 必须用指针, 不能用引用
(3) 何时 不 pass by reference:
1) iterator
: cheap-to-copy, pass by value 比 by const reference 更高 效
reference 本质是 指针
而 iterator 不过是指针的一种抽象
2) local obj
(4) 编译器 如何看待 操作符?
`二元操作符:`
编译器 把 操作符 作用在 左边
若 左边 重载了该操作符
把 操作符 编译成 调用 相应的 重载函数
ostream&
operator << (ostream& os, const complex& x)
{
return os << '(' << real(x) << ',' << imag(x) << ')';
}
// 编译器 找 << 的 matched 重载版本:
// 对 non-memFunc 而言, << 左操作数 cout 匹配 operator << () 的 para1: ostream& os
cout << c(2, 1) << endl;
4 返回值传递: return by value / return by reference (to const)
能传引用 就 传引用
5 友元 / friend
(1) 直接访问 friend 的 private 成员: 通过 pointer / reference / obj => 打破封装
(2) note: 同一 class 各 objects 互为友元
// (1)
inline complex&
_doapl (complex* ths, const complex& c)
{
ths->re += c.re;
ths->im += c.im;
return *ths;
}
// (2) 同一 class 各 objects 互为友元 ( c.re )
class complex
{
public:
...
int fun(const complex& c)
{
return c.re + c.im;
}
...
};
{
complex c1(2, 1);
complex c2;
c2.fun(c1);
}
6 class body 外 定义
class body 之外 的 函数:
用 类名限定 的是 mem func; 否则是 global func
inline complex&
_doapl (complex* ths, const complex& c)
{ //第 1/2 参数 会/不会 被改变
ths->re += c.re;
ths->im += c.im;
return *ths;
}
inline complex&
complex::operator += (const complex& c)
{
return _doapl(this, c);
}
5 操作符重载
1 mem func with this (implicit para: point to the obj calling the mem func)
func 中 某段
处理 提取成单独的函数, 以 实现 复用
complex c1(2, 1);
complex c2(5);
c2 += c1;
inline complex&
complex :: operator += (const complex& c)
{
//2. 右边 加到 左边 的这种动作 是一个通用动作,可以单独成函数,供其他 函数调用
return _doapl(this, c);
}
inline complex&
_doapl (complex* ths, const complex& c) //第1参数 会被改变,第2参数不会被改变
{
ths->re += c.re;
ths->im += c.im;
return *ths;
}
2 non-mem func without this
对某个 操作符重载,
只能 写为 `mem func 或 non-mem func` 之一,
但两者 `不能同时存在`
// 支持 c1 += c2;
inline complex
operator += (const complex& x, const complex& y)
{
return complex( real(x) + real(y), imag(x) + imag(y) );
}
// 支持 c1 += 5;
inline complex
operator += (const complex& x, double y)
{
return complex( real(x) + y, imag(x) );
}
3 temp object
不能 return by reference: 生命到下一行语句就结束了
inline complex
operator += (const complex& x, const complex& y)
{
return complex( real(x) + real(y),
imag(x) + imag(y) );
}
4 return by reference
发端 无需知道 收端 是以 什么形式 接收: 收端 以 value / reference 接收, 发端 都是同一形式 发送
vs. return by pointer: 发端 必须知道 传的是 pointer => 以 pointer 收, 必须以 pointer 发
// Note: 返回引用:以 [1] 支持 c3 += c2 += c1 [2] 加完之后更新 左值
inline complex&
_doapl (complex* ths, const complex& c)
{
...
return *ths;
}
complex::operator += (const complex& c)
{
return _doapl(this, c);
}
6 复习 Complex 类 的实现
// 1 防卫式 声明
#ifndef _COMPLEX_
#define _COMPLEX_
#endif
// 2 class name
class complex
{
};
// 3 mem ptr
class complex
{
private:
double re, im;
};
// 4 ctor
class complex
{
public:
complex (double r = 0, double i = 0)
: re (r), im (i) { }
private:
double re, im;
};
// 5 interface func
// 不改变 mem ptr 的 mem func: 写为 const mem func
// friend func:
class complex
{
friend complex& _doapl (complex*, const complex&);
public:
complex (double r = 0, double i = 0)
: re (r), im (i) { }
complex& operator += (const complex& );
double real () const { return re; }
double imag () const { return im; }
private:
double re, im;
};
6 class body 外 operator+= 定义
1) 设计 func 的 interface
[1] func name
complex::operator+=
[2] para
1> mem func => 只需要 右边
2> 先考虑 传 reference
3> 右边加到左边, 右边不动 => const 引用
complex::operator+=(const complex& c)
[3] return type
1> 得 左边这种 type
2> `return` 的 不是 函数内部创建的 local/temp obj,
而是 `已经存在的对象 (如 left operand obj)` 时,
=> 可以传 reference
complex&
complex::operator+=(const complex& c)
[4] 函数 body 之外 => 建议 为 inline
inline complex&
complex::operator+=(const complex& c)
2) 设计 func 的 definition
[1] 右边 加到 左边 是 通用动作,
可 抽取出 作 commonFunc
Note: 把 本 func 要做的事情 丢给 另一 func,
本 func 与 另一 func:
1] return type 相同,
2] 相同参数部分 type 相同
[2] 把 this 当 arg 传给 `commonFunc`
inline complex&
complex::operator+=(const complex& c)
{
return _doapl(this, c);
}
[3] 第1参数 会被改变,第2参数 不会被改变(=> const)
inline complex&
_doapl (complex* ths, const complex& c)
{
ths->re += c.re;
ths->im += c.im;
return *ths;
}
7 加
加 可以 是 复数 加 复数, 复数 加 实数 等,
=> 写成 non-mem func 更好
8 输出
cout << c1;
(1) 往 os 里 写时, os 状态 改变
=> os non-const reference
(2) 输出的 对象 状态不变 => const reference
(3) 对象 cout/os 类型为 ostream
operator << (ostream& os,
const complex& x)
(4)为 支持 cout << obj1 << endl;
=> cout << obj1 应 return cout 的类型 ostream
(5) cout 不是函数的 local 对象, 而是 本来就有的
=> 可以 return reference
ostream&
operator << (ostream& os, const complex& x)
{
}
(6) 按用户想要的方式输出
ostream&
operator << (ostream& os, const complex& x)
{
return os << '(' << real(x) << ',' << imag(x) << ')';
}
7 带 pointer 的类 — copy control: copy ctor / copy assignment / dtor
(1) class 带 pointer men, 多半是要 `动态内存分配`
=> 对象 生命结束前, dtor 被调用,
必须在 dtor 中 释放 动态分配的内存
(2) class with pointer members 必须有 copy ctor 和 copy op=
(3) 若无 自我赋值
, 则
左 / 右 pointer ( this->ptr / rhs.ptr) 指向 同一块内存
,
delete[] 左 ponter 后, 该 内存释放
,
再 strcpy(this->ptr, rhs.ptr) 会产生 undefined behavior
(4) 让 字符串 里 拥有 一个 poiner, 需要 内存时, 才去创建 另一空间 来放 字符串本身
因为 字符串 内容 有大有小, 这种设计 最好,
而不是在 字符串里 放一个 array
String s1(); // ctor,未 指定初值
String s2("hello"); // ctor
String s3(s1); // copy ctor
cout << s3 << endl;
s3 = s2; // copy assignment
cout << s3 << endl;
class Stirng
{
private:
char* ptr;
public:
String(const char* cstr = 0); // ctor
// copy ctor/assignment: 接收的是 自己这种东西
// => para 为 const String&
String(const String& str);
String& operator = (const String& str);
~String();
char* get_c_str() const { return ptr; }
};
// copy ctor
inline
String::String(const char* cstr = 0)
{
if(cstr)
{
ptr = new char[strlen(cstr) + 1];
strcpy(ptr, cstr);
}
else // 未 指定初值 eg: String s1();
{
ptr = new char[1];
*ptr = '\0';
}
}
inline
String:: ~String()
{
delete[] ptr;
}
// operator =
inline
String& String::operator = (const String& str)
{
if(&str == this) // 检测自我赋值
return *this;
delete[] ptr;
ptr = new char[ strlen(str.ptr) + 1];
strcpy(ptr, str.ptr);
return *this;
}
1.jpg
8 堆 栈 内存管理
8.1 object 生命期
1 栈 Stack
`某 scope 内` memory space
2 堆 Heap
`OS 提供 global memory space`
通常以 new/delete 分配/释放
`内存泄漏 : 只 分配 不 释放`
ptr 离开 scope 之后就消亡了, 但 ptr 所指 memory 还在`
3 stack object
`dtor 会 自动被调用 => 会被 自动 清理`
scope : 其所在的 scope
lifetime: 其所在的 scope
4 static local objects
scope : 其所在的 scope
lifetime: 持续到 整个程序结束
{
static Complex c2(1, 2);
}
5 global objects
scope : 持续到 整个程序结束
lifetime: 持续到 整个程序结束
6 heap objects
scope :
lifetime: 被 delete 时结束
8.2 new / delete / new [] / delete []
9 String 类 实现过程
(1) copy ctor
蓝本 是 自身 type 的 obj, 改变了 目的端 ptr
=> 不能是 const func
(2) copy assignment
1) 目的端 本来就存在 => return reference
2) 改变了 目的端 ptr => 不能是 const func
(3) C风格字符串
return pointer to 字符串
char* get_c_str() const { return ptr; }
第10讲 class/function template
第11讲 虚函数 与 多态
https://www.jianshu.com/p/eb69e02766e7
第12讲 组合 与 继承
https://www.jianshu.com/p/0f209eb83f47
第13将 委托
https://www.jianshu.com/p/0f209eb83f47
1. Comopsite - 设计模式
2. Prototype - 设计模式
网友评论