C++的编程思想和进阶编程

C++的编程思想和进阶编程

软件设计模式

  • 一个模式描述了一个不断发生的问题以及这个问题的解决方案;模式是前人的设计经验上总结出来的对于一些普遍存在的问题提供的通用的解决方案;比如单例模式、观察者模式等

  • 软件中有很多模式

    面向对象常见的23中设计模式;

    反模式;企业应用架构模式等

泛型编程的思想

  • 如果说面向对象是一种通过间接层来调用函数,以换取一种抽象,那么泛型编程则是更直接的抽象,它不会因为间接层而损失效率
  • 不同于面向对象的动态期多态(运行时多态),泛型编程是一种静态多态(编译时多态),通过编译器生成最直接的代码
  • 泛型编程可以将算法与特定类型、结构剥离,尽可能的复用代码

模板编程的难点很大程度上在于对编译器的理解,我们需要知道怎么帮助编译器提供需要生成代码的信息。

STL

  • STL算法是泛型,不与任何特定数据结构和对象绑定,不必在环境类型的情况下重写代码
  • STL算法可以量身定做,并且有很高的效率
  • STL可以进行扩充,你可以编写自己的组件并且能与STL标准的组件进行很好的配合

六大组件

容器、仿函数、算法、空间配置器、适配器、迭代器

容器
  • 容器用于存放数据;STL的容器分为两大类

    • 序列式容器

      其元素都是可排序的,STL提供了vector/list/deque等序列同期。而stack,queue,priority_queue则是容器适配器

    • 关联式容器

      每个数据元素都是由一个键(key)和值(value)组成,当元素被插入到容器时,按照其键以某种特定规则放入释放位置;常见的stl关联容器:set map

仿函数
  • 仿函数一般不会单独使用,主要是为了搭配STL算法使用
  • 函数指针不能满足STL对抽象性的要求,不能满足软件积木的要求,无法和STL其他组件搭配
  • 本质就是类重载了一个operator(),创建了一个行为类似于函数的对象
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <functional>
#include<algorithm>
#include <utility>
#include <iostream>
using namespace std;
struct Display
{
	void operator()(int i)
	{
		cout << i << " ";
	}
};

struct Display2
{
	void operator()(pair<string, double> info)
	{
		cout << info.first << ":  " << info.second << "  ";
	}
};

//struct cmpMap
//{
//	bool operator()(pair<string, double> a, pair<string, double> b)
//	{
//		return a.first.length() < b.first.length();
//	}
//};
int main()
{
	int iArr[] = { 1, 2,3,4,5 };

	vector<int> iVector(iArr, iArr + 4);
	list<int> iList(iArr, iArr + 4);
	deque<int> iDeque(iArr, iArr + 4);
	queue<int> iQueue(iDeque);     // 队列 先进先出
	stack<int> iStack(iDeque);         // 栈 先进后出
	priority_queue<int> iPQueue(iArr, iArr + 4);  // 优先队列,按优先权 

	for_each( iVector.begin(), iVector.end(), Display() );
	cout << endl;
	for_each(iList.begin(), iList.end(), Display());
	cout << endl;
	for_each(iDeque.begin(), iDeque.end(), Display());
	cout << endl;

	while ( !iQueue.empty() )
	{
		cout << iQueue.front() << " ";  // 1  2 3 4
		iQueue.pop();
	}
	cout << endl;

	while (!iStack.empty())
	{
		cout << iStack.top() << " ";    // 4 3  2  1
		iStack.pop();
	}
	cout << endl;

	while (!iPQueue.empty())
	{
		cout << iPQueue.top() << " "; // 4 3 2 1
		iPQueue.pop();
	}
	cout << endl;
    return 0;
}
#include <string>
#include<map>
#include <algorithm>
#include <iostream>
using namespace std;
struct Display
{
	void operator()(pair<string, double> info)
	{
		cout << info.first << ": " << info.second << endl;
	}
};
int main()
{
	map<string, double> studentSocres;
	studentSocres["LiMing"] = 95.0;
	studentSocres["LiHong"] = 98.5;
	studentSocres.insert( pair<string, double>("zhangsan", 100.0) );
	studentSocres.insert(pair<string, double>("Lisi", 98.6));
	studentSocres.insert(pair<string, double>("wangwu", 94.5));
	studentSocres.insert(map<string, double>::value_type("zhaoliu", 95.5) );
	studentSocres["wangwu"] = 88.5;
	for_each(studentSocres.begin(), studentSocres.end(), Display());
	cout << endl;

	map<string, double>::iterator iter;
	iter = studentSocres.find("zhaoliu");
	if (iter != studentSocres.end())
	{
		cout << "Found the score is: " << iter->second << endl;
	}
	else
	{
		cout << "Didn't find the key." << endl;
	}

	// 使用迭代器完成遍历查找的过程
	iter = studentSocres.begin();
	while (iter != studentSocres.end())
	{
		if (iter->second < 98.0)  // 去除不是优秀的同学
		{
			studentSocres.erase(iter++);  // 注意:迭代器失效问题
		}
		else
		{
			iter++;
		}
	}
	for_each(studentSocres.begin(), studentSocres.end(), Display());
	cout << endl;

	
	for (iter = studentSocres.begin(); iter != studentSocres.end(); iter++)
	{
		if (iter->second <= 98.5)
		{
			iter = studentSocres.erase(iter);  // 注意:迭代器失效问题
		}
	}
	for_each(studentSocres.begin(), studentSocres.end(), Display());
	cout << endl;

	// find得到并删除元素
	//iter = studentSocres.find("LiHong");
	//studentSocres.erase(iter);
	//for_each(studentSocres.begin(), studentSocres.end(), Display());

	//int n = studentSocres.erase("LiHong1");
	//cout << n << endl;
	//for_each(studentSocres.begin(), studentSocres.end(), Display());

	studentSocres.erase(studentSocres.begin(), studentSocres.end());
	for_each(studentSocres.begin(), studentSocres.end(), Display());
	cout << endl;

    return 0;
}
算法
  • STL中算法大致分为4类:包含于<algorithm> <numeric> <functional>

    • 非可变排序算法:指的是不直接修改其操作的容器内容的算法
    • 可变排序算法:修改他们操作的容器内容的算法
    • 排序算法:包括堆序列进行排序和合并的算法,搜索算法以及有序序列上的集合操作
    • 数值算法:对容器内容进行数值计算
  • 最长见的算法包括:

    查找、排序和通用算法,排列组合算法,集合算法等

#include <vector>
#include <algorithm>
#include <functional>
#include <numeric>
#include<iostream>
using namespace std;
int main()
{   
	// transform和lambda表达式
	int ones[] = { 1, 2, 3, 4, 5 };
	int twos[] = { 10, 20, 30, 40, 50 };
	int results[5];
	transform(ones, ones + 5, twos, results, std::plus<int>()); // 数组元素依次相加并返回
	for_each(results, results + 5,
		[ ](int a)->void {
		cout << a << endl; } ); // lambda表达式(匿名函数)
	cout << endl;

	// find
	int arr[] = { 0, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8 };
	int len = sizeof(arr) / sizeof(arr[0]);
	vector<int> iA(arr + 2, arr + 6);   // {2,3,3,4}
	//vector<int> iA;
	//iA.push_back(1);
	//iA.push_back(9); // {1, 9}
	cout << count(arr, arr + len, 6) << endl; // 统计6的个数
	cout << count_if(arr, arr + len, bind2nd(less<int>(),  7) ) << endl; // 统计<7的个数
	cout << binary_search(arr, arr + len, 9) << endl;   // 9找不到
	cout << *search(arr, arr + len, iA.begin(), iA.end()) << endl; // 查找子序列
	cout << endl;
    return 0;
}

#include <algorithm>
#include <iostream>
using namespace std;
// 输入一个不存在重复字符的字符串,打印出字符串中字符的全排列。
//比如:
//输入: "123"   3*2*1 = 3!
//输出:  123
//          132
//          213
//          231
//          321
//          312
//f(123) = 1+f(23), f(23) = 2+f(3), f(3)  = 3  递归
void swap(char* a, char* b)
{
	char temp = *a;
	*a = *b;
	*b = temp;
}
void Permutation(char* pStr, char* pPostion)
{
	// 基准点
	if (*pPostion == '\0')
	{
		cout << pStr << endl;
	}
	else
	{
		for (char* pChar = pPostion; *pChar != '\0'; pChar++)
		{
			// 依次和后面的字符交换
			swap(*pChar, *pPostion);

			Permutation(pStr, pPostion + 1);

			// 换回来
			swap(*pChar, *pPostion);
		}
	}
}
int main()
{
	char test[] = "132";
	Permutation(test, test);
	cout << endl;

	// 用STL输出全排列
	// 注意:必须要保证数组顺序,
	do
	{
		cout << test[0] << test[1] << test[2] << endl;
	} while (next_permutation(test, test + 3));
	cout << endl;

	char test2[] = "321";
	// 注意:必须要保证数组顺序,
	do
	{
		cout << test2[0] << test2[1] << test2[2] << endl;
	} while (prev_permutation(test2, test2 + 3));

    return 0;
}

迭代器
  • 是一种smart point,用于访问顺序容器和关联容器中的元素,相当于容器和操作容器的算法之间的中介

  • 迭代器按照定义方式分为四种:

    1. 正向迭代器:iterator
    2. 常量正向迭代器:const_iterator
    3. 反向迭代器:reverse_iterator
    4. 常量反向迭代器:const_reverse_iterator
#include <list>
#include <iostream>
using namespace std;

int main()
{
	list<int> v;
	v.push_back(3);
	v.push_back(4);
	v.push_front(2);
	v.push_front(1);  // 1, 2, 3, 4
	list<int>::const_iterator it;
	for (it = v.begin(); it != v.end(); it++)
	{
		//*it += 1;
		cout << *it << " ";
	}
	cout << endl;
	// 注意:迭代器不支持<
	//for (it = v.begin(); it < v.end(); it++)
	//{
	//	cout << *it << " ";
	//}
	cout <<v.front() << endl;
	v.pop_front();  // 从顶部去除
	list<int>::reverse_iterator it2;
	for (it2 = v.rbegin(); it2 != v.rend(); it2++)
	{
		*it2 += 1;
		cout << *it2 << " ";                          // 5 4 3
	}
	cout << endl;
    return 0;
}

适配器
  • stack 栈:一种先进后出的容器,底层为deque
  • queue 队列:一种先进先出的容器,底层为deque
  • priority_queue 优先队列:一种特殊的队列,他能够在队列中进行排序(堆排序),底层实现结构式vector或者deque
#include <functional>
#include <stack>
#include <queue>
#include <iostream>
using namespace std;
int main()
{
	//stack<int> s;
	//queue<int> q;
	priority_queue<int> pq;  // 默认是最大值优先
	priority_queue<int, vector<int>, less<int> > pq2; //   最大值优先
	priority_queue<int, vector<int>, greater<int> > pq3; // 最小值优先
	pq.push(2);
	pq.push(1);
	pq.push(3);
	pq.push(0);
	while (!pq.empty())
	{
		int top = pq.top();
		cout << " top is: " << top<< endl;
		pq.pop();
	}
	cout << endl;
	pq2.push(2);
	pq2.push(1);
	pq2.push(3);
	pq2.push(0);
	while (!pq2.empty())
	{
		int top = pq2.top();
		cout << " top is: " << top << endl;
		pq2.pop();
	}
	cout << endl;
	pq3.push(2);
	pq3.push(1);
	pq3.push(3);
	pq3.push(0);
	while (!pq3.empty())
	{
		int top = pq3.top();
		cout << " top is: " << top << endl;
		pq3.pop();
	}
	cout << endl;
    return 0;
}
空间配置器(allocator)

《STL源码分析》

  • 从使用角度看,allocator隐藏在其他组件中默默工作,不需要关心,但是从stl实现角度看,它是首先分析的组件
  • allocator的分析可以提现C++在性能和资源管理上优化思想

jjalloc.h

#pragma once
#ifndef _JJALLOC
#define _JJALLOC
#include<new> //for placement new
#include<cstddef> //for ptrdiff_t ,size_t
#include<cstdlib> //for exit()
#include<climits> //for UINX_MAX
#include<iostream> //for cerr

namespace  JJ
{
	template<class T>
	inline T* _allocate(ptrdiff_t size, T*)
	{
		set_new_handler(0);
		T* tmp = (T*)(::operator new((size_t)(size * sizeof(T))));
		if (tmp == 0)
		{
			cerr << "out of memory" << endl;
			exit(1);
		}
		return tmp;
	}
	template<class T>
	inline void _deallocate(T* buffer)
	{
		::operator delete(buffer);

	}

	template<class T1, class T2>
	inline void _construct(T1* p, const T2& value)
	{
		new(p) T1(value);//placement new,invoke constuctor of T1
	}

	template<class T>
	inline void _destroy(T* ptr)
	{
		ptr->~T();
	}

	template<class T>
	class allocator {
	public:
		typedef T value_type;
		typedef T* pointer;
		typedef const T* const_pointer;
		typedef T& reference;
		typedef const T& const_reference;
		typedef size_t size_type;
		typedef ptrdiff_t difference_type;

		//rebind allocator of type U
		template<class U>
		struct rebind {
			typedef allocator<U> other;
		};
		//需要加上以下2个函数,windows的编译器用到了allocator不同类型的拷贝, 
		allocator()
		{
			return;
		}

		template <class U>
		allocator(const allocator<U>& c)
		{
		}

		//hint user for locality,第2个参数是个提示,实现上可能会利用它来增进区域性(locality),或完全忽略之
		pointer allocate(size_type n, const void* hint = 0)
		{
			return _allocate((difference_type)n, (pointer)0);
		}

		void deallocate(pointer p, size_type n)
		{
			_deallocate(p);
		}

		void construct(pointer p, const T& value)
		{
			_construct(p, value);
		}
		void destroy(pointer p)
		{
			_destroy(p);
		}
		pointer address(reference x) { return (pointer)&x; }
		const_pointer const_address(const_reference x) { return (const_pointer)&x; }

		size_type max_size() const {
			return size_type(UINT_MAX / sizeof(T));
		}
	};
}//#end of namespace JJ
#endif
#include "jjalloc.h"
#include <vector>
using namespace std;

int main()
{
	int ia[5] = { 0, 1, 2, 3, 4 };
	unsigned int i;
	vector<int, JJ::allocator<int> > iv(ia, ia + 5);
	for (i = 0; i < iv.size(); i++)
	{
		cout << iv[i] << " ";
	}
	cout << endl;


    return 0;
}

总结

  • STL的六大组件给软件带来了新的多态和复用,是现代C++语言高效的精髓
  • 泛型和STL的学习路线很陡,建议初学者先学会基本的使用和简单的扩展
  • 掌握了一定基础的情况下,可以通过进一步学习和分析源码,编写自己的组件来提升能力

C++多线程

  • C++11中thread的使用
  • mutex等锁的使用
  • 进程与线程,同步与异步
  • 线程交换与移动
#include <thread>
#include <mutex>
#include <iostream>
using namespace std;

mutex g_mutex;
void T1()
{
	g_mutex.lock();
	cout << "T1 Hello" << endl;
	g_mutex.unlock();
}
void T2(const char* str)
{
	g_mutex.lock();
	cout << "T2 " << str << endl;
	g_mutex.unlock();
}
int main()
{
	thread t1(T1);
	thread t2(T2, "Hello World");
	t1.join();
	//t2.join();
	t2.detach();
	cout << "Main Hi" << endl;
    return 0;
}
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
// 存钱
void Deposit(mutex& m, int& money)
{
	// 锁的粒度尽可能的最小化
	for(int index = 0; index < 100; index++)
	{
		m.lock();
		money += 1;
		m.unlock();
	}
}
// 取钱
void Withdraw(mutex& m, int& money)
{
	// 锁的粒度尽可能的最小化
	for (int index = 0; index < 100; index++)
	{
		m.lock();
		money -= 2;
		m.unlock();
	}
}
int main()
{
	// 银行存取款
	//int money = 2000;
	//mutex m;
	//cout << "Current money is: " << money << endl;
	//thread t1(Deposit, ref(m), ref(money));
	//thread t2(Withdraw, ref(m), ref(money));
	//t1.join();
	//t2.join();
	//cout << "Finally money is: " << money << endl;
	//线程交换 
	//thread tW1([]()
	//{
	//	cout << "ThreadSwap1 " << endl;
	//});
	//thread tW2([]()
	//{
	//	cout << "ThreadSwap2 " << endl;
	//});
	//cout << "ThreadSwap1' id is " << tW1.get_id() << endl;
	//cout << "ThreadSwap2' id is " << tW2.get_id() << endl;
	//cout << "Swap after:" << endl;
	//swap(tW1, tW2); 
	//cout << "ThreadSwap1' id is " << tW1.get_id() << endl;
	//cout << "ThreadSwap2' id is " << tW2.get_id() << endl;
	//tW1.join();
	//tW2.join();
	 线程移动
	thread tM1( []() { ; } );
	//tM1.join();
	cout << "ThreadMove1' id is " << tM1.get_id() << endl;
	cout << "Move after:" << endl;
	thread tM2 = move(tM1);
	cout << "ThreadMove2' id is " << tM2.get_id() << endl;
	cout << "ThreadMove1' id is " << tM1.get_id() << endl;
	tM2.join();
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++编程思想 目 录 译者序 前言 第1章 对象的演化 1 1.1 基本概念 1 1.1.1 对象:特性+行为 1 1.1.2 继承:类型关系 1 1.1.3 多态性 2 1.1.4 操作概念:OOP程序像什么 3 1.2 为什么C++会成功 3 1.2.1 较好的C 3 1.2.2 采用渐进的学习方式 4 1.2.3 运行效率 4 1.2.4 系统更容易表达和理解 4 1.2.5 “库”使你事半功倍 4 1.2.6 错误处理 5 1.2.7 大程序设计 5 1.3 方法学介绍 5 1.3.1 复杂性 5 1.3.2 内部原则 6 1.3.3 外部原则 7 1.3.4 对象设计的五个阶段 9 1.3.5 方法承诺什么 10 1.3.6 方法应当提供什么 10 1.4 起草:最小的方法 12 1.4.1 前提 13 1.4.2 高概念 14 1.4.3 论述(treatment) 14 1.4.4 结构化 14 1.4.5 开发 16 1.4.6 重写 17 1.4.7 逻辑 17 1.5 其他方法 17 1.5.1 Booch 18 1.5.2 责任驱动的设计(RDD) 19 1.5.3 对象建模技术(OMT) 19 1.6 为向OOP转变而采取的策略 19 1.6.1 逐步进入OOP 19 1.6.2 管理障碍 20 1.7 小结 21 第2章 数据抽象 22 2.1 声明与定义 22 2.2 一个袖珍C库 23 2.3 放在一起:项目创建工具 29 2.4 什么是非正常 29 2.5 基本对象 30 2.6 什么是对象 34 2.7 抽象数据类型 35 2.8 对象细节 35 2.9 头文件形式 36 2.10 嵌套结构 37 2.11 小结 41 2.12 练习 41 第3章 隐藏实现 42 3.1 设置限制 42 3.2 C++的存取控制 42 3.3 友元 44 3.3.1 嵌套友元 45 3.3.2 它是纯的吗 48 3.4 对象布局 48 3.5 类 48 3.5.1 用存取控制来修改stash 50 3.5.2 用存取控制来修改stack 51 3.6 句柄类(handle classes) 51 3.6.1 可见的实现部分 51 3.6.2 减少重复编译 52 3.7 小结 54 3.8 练习 54 第4章 初始化与清除 55 4.1 用构造函数确保初始化 55 4.2 用析构函数确保清除 56 4.3 清除定义块 58 4.3.1 for循环 59 4.3.2 空间分配 60 4.4 含有构造函数和析构函数的stash 61 4.5 含有构造函数和析构函数的stack 63 4.6 集合初始化 65 4.7 缺省构造函数 67 4.8 小结 68 4.9 练习 68 第5章 函数重载与缺省参数 69 5.1 范围分解 69 5.1.1 用返回值重载 70 5.1.2 安全类型连接 70 5.2 重载的例子 71 5.3 缺省参数 74 5.4 小结 81 5.5 练习 82 第6章 输入输出流介绍 83 6.1 为什么要用输入输出流 83 6.2 解决输入输出流问题 86 6.2.1 预先了解操作符重载 86 6.2.2 插入符与提取符 87 6.2.3 通常用法 88 6.2.4 面向行的输入 90 6.3 文件输入输出流 91 6.4 输入输出流缓冲 93 6.5 在输入输出流中查找 94 6.6 strstreams 96 6.6.1 为用户分配的存储 96 6.6.2 自动存储分配 98 6.7 输出流格式化 100 6.7.1 内部格式化数据 101 6.7.2 例子 102 6.8 格式化操纵算子 106 6.9 建立操纵算子 108 6.10 输入输出流实例 111 6.10.1 代码生成 111 6.10.2 一个简单的数据记录 117 6.11 小结 123 6.12 练习 123 第7章 常量 124 7.1 值替代 124 7.1.1 头文件里的const 124 7.1.2 const的安全性 125 7.1.3 集合 126 7.1.4 与C语言的区别 126 7.2 指针 127 7.2.1 指向const的指针 127 7.2.2 const指针 127 7.2.3 赋值和类型检查 128 7.3 函数参数和返回值 128 7.3.1 传递const值 128 7.3.2 返回const值 129 7.3.3 传递和返回地址 131 7.4 类 133 7.4.1 类里的const和enum 133 7.4.2 编译期间类里的常量 134 7.4.3 const对象和成员函数 136 7.4.4 只读存储能力 139 7.5 可变的(volatile) 140 7.6 小结 141 7.7 练习 141 第8章 内联函数 142 8.1 预处理器的缺陷 142 8.2 内联函数 144 8.2.1 类内部的内联函数 145 8.2.2 存取函数 146 8.3 内联函数和编译器 150 8.3.1 局限性 150 8.3.2 赋值顺序 150 8.3.3 在构造函数和析构函数里隐藏行为 151 8.4 减少混乱 152 8.5 预处理器的特点 153 8.6 改进的错误检查 154 8.7 小结 155 8.8 练习 155 第9章 命名控制 157 9.1 来自C语言中的静态成员 157 9.1.1 函数内部的静态变量 157 9.1.2 控制连接 160 9.1.3 其他的存储类型指定符 161 9.2 名字空间 161 9.2.1 产生一个名字空间 162 9.2.2 使用名字空间 163 9.3 C++中的静态成员 166 9.3.1 定义静态数据成员的存储 166 9.3.2 嵌套类和局部类 168 9.3.3 静态成员函数 169 9.4 静态初始化的依赖因素 171 9.5 转换连接指定 174 9.6 小结 174 9.7 练习 174 第10章 引用和拷贝构造函数 176 10.1 C++中的指针 176 10.2 C++中的引用 176 10.2.1 函数中的引用 177 10.2.2 参数传递准则 178 10.3 拷贝构造函数 179 10.3.1 传值方式传递和返回 179 10.3.2 拷贝构造函数 182 10.3.3 缺省拷贝构造函数 187 10.3.4 拷贝构造函数方法的选择 188 10.4 指向成员的指针 ......
C++编程思想,目 录 译者序 前言 第1章 对象的演化 1 1.1 基本概念 1 1.1.1 对象:特性+行为 1 1.1.2 继承:类型关系 1 1.1.3 多态性 2 1.1.4 操作概念:OOP程序像什么 3 1.2 为什么C++会成功 3 1.2.1 较好的C 3 1.2.2 采用渐进的学习方式 4 1.2.3 运行效率 4 1.2.4 系统更容易表达和理解 4 1.2.5 “库”使你事半功倍 4 1.2.6 错误处理 5 1.2.7 大程序设计 5 1.3 方法学介绍 5 1.3.1 复杂性 5 1.3.2 内部原则 6 1.3.3 外部原则 7 1.3.4 对象设计的五个阶段 9 1.3.5 方法承诺什么 10 1.3.6 方法应当提供什么 10 1.4 起草:最小的方法 12 1.4.1 前提 13 1.4.2 高概念 14 1.4.3 论述(treatment) 14 1.4.4 结构化 14 1.4.5 开发 16 1.4.6 重写 17 1.4.7 逻辑 17 1.5 其他方法 17 1.5.1 Booch 18 1.5.2 责任驱动的设计(RDD) 19 1.5.3 对象建模技术(OMT) 19 1.6 为向OOP转变而采取的策略 19 1.6.1 逐步进入OOP 19 1.6.2 管理障碍 20 1.7 小结 21 第2章 数据抽象 22 2.1 声明与定义 22 2.2 一个袖珍C库 23 2.3 放在一起:项目创建工具 29 2.4 什么是非正常 29 2.5 基本对象 30 2.6 什么是对象 34 2.7 抽象数据类型 35 2.8 对象细节 35 2.9 头文件形式 36 2.10 嵌套结构 37 2.11 小结 41 2.12 练习 41 第3章 隐藏实现 42 3.1 设置限制 42 3.2 C++的存取控制 42 3.3 友元 44 3.3.1 嵌套友元 45 3.3.2 它是纯的吗 48 3.4 对象布局 48 3.5 类 48 3.5.1 用存取控制来修改stash 50 3.5.2 用存取控制来修改stack 51 3.6 句柄类(handle classes) 51 3.6.1 可见的实现部分 51 3.6.2 减少重复编译 52 3.7 小结 54 3.8 练习 54 第4章 初始化与清除 55 4.1 用构造函数确保初始化 55 4.2 用析构函数确保清除 56 4.3 清除定义块 58 4.3.1 for循环 59 4.3.2 空间分配 60 4.4 含有构造函数和析构函数的stash 61 4.5 含有构造函数和析构函数的stack 63 4.6 集合初始化 65 4.7 缺省构造函数 67 4.8 小结 68 4.9 练习 68 第5章 函数重载与缺省参数 69 5.1 范围分解 69 5.1.1 用返回值重载 70 5.1.2 安全类型连接 70 5.2 重载的例子 71 5.3 缺省参数 74 5.4 小结 81 5.5 练习 82 第6章 输入输出流介绍 83 6.1 为什么要用输入输出流 83 6.2 解决输入输出流问题 86 6.2.1 预先了解操作符重载 86 6.2.2 插入符与提取符 87 6.2.3 通常用法 88 6.2.4 面向行的输入 90 6.3 文件输入输出流 91 6.4 输入输出流缓冲 93 6.5 在输入输出流中查找 94 6.6 strstreams 96 6.6.1 为用户分配的存储 96 6.6.2 自动存储分配 98 6.7 输出流格式化 100 6.7.1 内部格式化数据 101 6.7.2 例子 102 6.8 格式化操纵算子 106 6.9 建立操纵算子 108 6.10 输入输出流实例 111 6.10.1 代码生成 111 6.10.2 一个简单的数据记录 117 6.11 小结 123 6.12 练习 123 第7章 常量 124 7.1 值替代 124 7.1.1 头文件里的const 124 7.1.2 const的安全性 125 7.1.3 集合 126 7.1.4 与C语言的区别 126 7.2 指针 127 7.2.1 指向const的指针 127 7.2.2 const指针 127 7.2.3 赋值和类型检查 128 7.3 函数参数和返回值 128 7.3.1 传递const值 128 7.3.2 返回const值 129 7.3.3 传递和返回地址 131 7.4 类 133 7.4.1 类里的const和enum 133 7.4.2 编译期间类里的常量 134 7.4.3 const对象和成员函数 136 7.4.4 只读存储能力 139 7.5 可变的(volatile) 140 7.6 小结 141 7.7 练习 141 第8章 内联函数 142 8.1 预处理器的缺陷 142 8.2 内联函数 144 8.2.1 类内部的内联函数 145 8.2.2 存取函数 146 8.3 内联函数和编译器 150 8.3.1 局限性 150 8.3.2 赋值顺序 150 8.3.3 在构造函数和析构函数里隐藏行为 151 8.4 减少混乱 152 8.5 预处理器的特点 153 8.6 改进的错误检查 154 8.7 小结 155 8.8 练习 155 第9章 命名控制 157 9.1 来自C语言中的静态成员 157 9.1.1 函数内部的静态变量 157 9.1.2 控制连接 160 9.1.3 其他的存储类型指定符 161 9.2 名字空间 161 9.2.1 产生一个名字空间 162 9.2.2 使用名字空间 163 9.3 C++中的静态成员 166 9.3.1 定义静态数据成员的存储 166 9.3.2 嵌套类和局部类 168 9.3.3 静态成员函数 169 9.4 静态初始化的依赖因素 171 9.5 转换连接指定 174 9.6 小结 174 9.7 练习 174 第10章 引用和拷贝构造函数 176 10.1 C++中的指针 176 10.2 C++中的引用 176 10.2.1 函数中的引用 177 10.2.2 参数传递准则 178 10.3 拷贝构造函数 179 10.3.1 传值方式传递和返回 179 10.3.2 拷贝构造函数 182 10.3.3 缺省拷贝构造函数 187 10.3.4 拷贝构造函数方法的选择 188 10.4 指向成员的指针
目 录 译者序 前言 第1章 对象的演化 1 1.1 基本概念 1 1.1.1 对象:特性+行为 1 1.1.2 继承:类型关系 1 1.1.3 多态性 2 1.1.4 操作概念:OOP程序像什么 3 1.2 为什么C++会成功 3 1.2.1 较好的C 3 1.2.2 采用渐进的学习方式 4 1.2.3 运行效率 4 1.2.4 系统更容易表达和理解 4 1.2.5 “库”使你事半功倍 4 1.2.6 错误处理 5 1.2.7 大程序设计 5 1.3 方法学介绍 5 1.3.1 复杂性 5 1.3.2 内部原则 6 1.3.3 外部原则 7 1.3.4 对象设计的五个阶段 9 1.3.5 方法承诺什么 10 1.3.6 方法应当提供什么 10 1.4 起草:最小的方法 12 1.4.1 前提 13 1.4.2 高概念 14 1.4.3 论述(treatment) 14 1.4.4 结构化 14 1.4.5 开发 16 1.4.6 重写 17 1.4.7 逻辑 17 1.5 其他方法 17 1.5.1 Booch 18 1.5.2 责任驱动的设计(RDD) 19 1.5.3 对象建模技术(OMT) 19 1.6 为向OOP转变而采取的策略 19 1.6.1 逐步进入OOP 19 1.6.2 管理障碍 20 1.7 小结 21 第2章 数据抽象 22 2.1 声明与定义 22 2.2 一个袖珍C库 23 2.3 放在一起:项目创建工具 29 2.4 什么是非正常 29 2.5 基本对象 30 2.6 什么是对象 34 2.7 抽象数据类型 35 2.8 对象细节 35 2.9 头文件形式 36 2.10 嵌套结构 37 2.11 小结 41 2.12 练习 41 第3章 隐藏实现 42 3.1 设置限制 42 3.2 C++的存取控制 42 3.3 友元 44 3.3.1 嵌套友元 45 3.3.2 它是纯的吗 48 3.4 对象布局 48 3.5 类 48 3.5.1 用存取控制来修改stash 50 3.5.2 用存取控制来修改stack 51 3.6 句柄类(handle classes) 51 3.6.1 可见的实现部分 51 3.6.2 减少重复编译 52 3.7 小结 54 3.8 练习 54 第4章 初始化与清除 55 4.1 用构造函数确保初始化 55 4.2 用析构函数确保清除 56 4.3 清除定义块 58 4.3.1 for循环 59 4.3.2 空间分配 60 4.4 含有构造函数和析构函数的stash 61 4.5 含有构造函数和析构函数的stack 63 4.6 集合初始化 65 4.7 缺省构造函数 67 4.8 小结 68 4.9 练习 68 第5章 函数重载与缺省参数 69 5.1 范围分解 69 5.1.1 用返回值重载 70 5.1.2 安全类型连接 70 5.2 重载的例子 71 5.3 缺省参数 74 5.4 小结 81 5.5 练习 82 第6章 输入输出流介绍 83 6.1 为什么要用输入输出流 83 6.2 解决输入输出流问题 86 6.2.1 预先了解操作符重载 86 6.2.2 插入符与提取符 87 6.2.3 通常用法 88 6.2.4 面向行的输入 90 6.3 文件输入输出流 91 6.4 输入输出流缓冲 93 6.5 在输入输出流中查找 94 6.6 strstreams 96 6.6.1 为用户分配的存储 96 6.6.2 自动存储分配 98 6.7 输出流格式化 100 6.7.1 内部格式化数据 101 6.7.2 例子 102 6.8 格式化操纵算子 106 6.9 建立操纵算子 108 6.10 输入输出流实例 111 6.10.1 代码生成 111 6.10.2 一个简单的数据记录 117 6.11 小结 123 6.12 练习 123 第7章 常量 124 7.1 值替代 124 7.1.1 头文件里的const 124 7.1.2 const的安全性 125 7.1.3 集合 126 7.1.4 与C语言的区别 126 7.2 指针 127 7.2.1 指向const的指针 127 7.2.2 const指针 127 7.2.3 赋值和类型检查 128 7.3 函数参数和返回值 128 7.3.1 传递const值 128 7.3.2 返回const值 129 7.3.3 传递和返回地址 131 7.4 类 133 7.4.1 类里的const和enum 133 7.4.2 编译期间类里的常量 134 7.4.3 const对象和成员函数 136 7.4.4 只读存储能力 139 7.5 可变的(volatile) 140 7.6 小结 141 7.7 练习 141 第8章 内联函数 142 8.1 预处理器的缺陷 142 8.2 内联函数 144 8.2.1 类内部的内联函数 145 8.2.2 存取函数 146 8.3 内联函数和编译器 150 8.3.1 局限性 150 8.3.2 赋值顺序 150 8.3.3 在构造函数和析构函数里隐藏行为 151 8.4 减少混乱 152 8.5 预处理器的特点 153 8.6 改进的错误检查 154 8.7 小结 155 8.8 练习 155 第9章 命名控制 157 9.1 来自C语言中的静态成员 157 9.1.1 函数内部的静态变量 157 9.1.2 控制连接 160 9.1.3 其他的存储类型指定符 161 9.2 名字空间 161 9.2.1 产生一个名字空间 162 9.2.2 使用名字空间 163 9.3 C++中的静态成员 166 9.3.1 定义静态数据成员的存储 166 9.3.2 嵌套类和局部类 168 9.3.3 静态成员函数 169 9.4 静态初始化的依赖因素 171 9.5 转换连接指定 174 9.6 小结 174 9.7 练习 174 第10章 引用和拷贝构造函数 176 10.1 C++中的指针 176 10.2 C++中的引用 176 10.2.1 函数中的引用 177 10.2.2 参数传递准则 178 10.3 拷贝构造函数 179 10.3.1 传值方式传递和返回 179 10.3.2 拷贝构造函数 182 10.3.3 缺省拷贝构造函数 187 10.3.4 拷贝构造函数方法的选择 188 10.4 指向成员的指针
Bruce Eckel 《Thinking in Java》(Java编程思想)作者。Eckel有20年专业编程经验,并自1986年起教育人们如何撰写面向对象程序,足迹遍及全球,成为一位知名的 C++教师和顾问,如今兼涉Java。他是C++标准委员会拥有表决权的成员之一,曾经写过另五本面向对象编程书籍,发表过150篇以上的文章,是多本计算机杂志的专栏作家。Eckel开创Software Development Conference的C++、Java、Python等多项研讨活动。拥有应用物理学学士和计算机工程学硕士学位。 目录 译者序 前言 第1章 对象导言 第2章 对象的创建与使用 第3章 C++中的C 第4章 数据抽象 第5章 隐藏实现 第6章 初始化与清除 第7章 函数重载与默认参数 第8章 常量 第9章 内联函数 第10章 名字控制 第11章 引用和拷贝构造函数 第12章 运算符重载 第13章 动态对象创建 第14章 继承和组合 第15章 多态性和虚函数 第16章 模板介绍 附录A 编码风格 附录B 编程准则 附录C 推荐读物 索引 第2卷:实用编程技术 出版者的话 专家指导委员会 译者序 前言 第一部分 建立稳定的系统 第1章 异常处理 第2章 防御性编程 第二部分 标准C++库 第3章 深入理解字符串 第4章 输入输出流 第5章 深入理解模板 第6章 通用算法 第7章 通用容器 第三部分 专题 第8章 运行时类型识别 第9章 多重继承 第10章 设计模式 第11章 并发 附录 附录A 推荐读物 附录B 其他 索引 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

turbolove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值