163 lines
8.1 KiB
TeX
163 lines
8.1 KiB
TeX
\documentclass[a4paper,12pt]{article}
|
||
\usepackage[utf8]{inputenc}
|
||
\usepackage[UTF8]{ctexcap}
|
||
\usepackage{amsmath}
|
||
\usepackage{amsfonts}
|
||
\usepackage{amssymb}
|
||
|
||
\usepackage{xcolor}
|
||
%opening
|
||
\title{C++学习笔记}
|
||
\author{行走的芦苇}
|
||
|
||
\begin{document}
|
||
|
||
\maketitle
|
||
|
||
%\begin{abstract}
|
||
|
||
%\end{abstract}
|
||
|
||
\section{基本概念}
|
||
在协作完成一个大的软件时,应如何合理地设计程序结构,并保证每一个子程序之间都能正确地共享和交换数据,这是编程的\textcolor{red}{核心问题}。
|
||
|
||
程序员的任务是将计算表达出来,并且做到:
|
||
\begin{itemize}
|
||
\item 正确
|
||
\item 简单
|
||
\item 高效
|
||
\end{itemize}
|
||
一个看似矛盾的事实:关注代码结构和代码“质量”是程序取得成功的最快捷径。\\
|
||
程序的组织体现了程序员的编程思路、目前手段主要是把大的计算任务划分为许多小任务,这一技术主要包括两类方法。
|
||
\begin{itemize}
|
||
\item[抽象]:即不需要了解的程序具体实现细节被隐藏在相应的接口后边
|
||
\item[分治]:把一个大问题分为几个小问题分别解决
|
||
\end{itemize}
|
||
对于一个好的程序员和系统设计师,软件的\textbf{结构问题}是在开发过程中始终要关注的最重要问题。
|
||
|
||
将问题不断的分解、细化,直到问题小到能够被我们很好的理解和解决为止\\
|
||
表达式是程序的最小组成单元,表达式就是从一些操作数计算一个值。\\
|
||
左值:一个变量;右值,一个变量的值\\
|
||
符号常量表示那些在初始化后值不再改变的数值量。\\
|
||
表达式语句主要包括赋值语句、I/O语句和函数调用。声明语句呢??
|
||
|
||
除了合法输入情况以外,程序必须经过各种非法输入的检验。\\
|
||
switch语句括号中值必须是整型、字符型或枚举类型。特别的,不能使用字符串型\\
|
||
\begin{verbatim}
|
||
char* ca = reinterpret_cast<char*>(&a);
|
||
\end{verbatim}
|
||
判定一个自然数是质量的方法:
|
||
对于任一自然数$N$,$0 <m <N-1$,若$ \frac{N}{m}\neq 0$,则$N$为质数。\par
|
||
\textbf{算法描述}
|
||
\begin{description}
|
||
\item[输入]输入正整数$N$,$N>=3$
|
||
\item[判定]对于$\forall M~~2<M<N-1$,若$N\%M == 0$,则$N$为质数。
|
||
\end{description}
|
||
\textcolor{red}{为什么vector不做越界检查呢?}
|
||
|
||
错误的来源:
|
||
\begin{itemize}
|
||
\item 缺少规划,如果事先没有规划好程序做什么,就不能检查所有的“死角”,并确认所有可能的情况都会被正确处理
|
||
\item 不完备的程序,不可能考虑所有可能的情况
|
||
\item 意外的参数,如果为一个函数输入了一个不能处理的参数
|
||
\item 意外的输入,键盘、文件、图形界面和网络都有可能出错
|
||
\item 意外状态,多数程序都保留了很多系统的各个部分的状态,如果这些状态数据出错或不完整会导致程序出错
|
||
\item 逻辑错误,程序没有按照我们期望的逻辑运行。
|
||
\end{itemize}
|
||
做过分析(理解问题)和设计(决定解决方案的整体结构)以后才进行程序设计。分析判断应该做什么并且给出对当前问题理解的描述,也称为需求集合或规范,设计给出系统的整体结构图,并确定具体的实现内容以及它们之间的相互关系,实现编写代码、调试并测试,确保程序完成预期的功能。
|
||
|
||
定义一个文法来定义表达式的语法,然后在程序中实现这些文法规则。
|
||
|
||
如何来读入一个文法呢?基本文法是这样的:对于给定输入,从顶层规则开始,搜索与输入单词匹配的规则。根据文法读取单词流的方式称为语法分析,实现的程序称为分析器或语法分析器。
|
||
|
||
阅读代码是积累编程技巧的有效途径。
|
||
|
||
尤其危险的程序是在很多情况下给出正确的结果。
|
||
|
||
最基本的做法是阅读代码并猜测错误在哪里,但通常这不是一个好方法。因为我们必须理解程序代码在做什么。错误分析通常也是能找出正确求解方案的最好方法。
|
||
|
||
类的定义主要说明类能够做什么,成员函数定义则指明如何做。
|
||
|
||
程序设计的本质:不断地寻找更简单的方法。
|
||
|
||
大多数程序设计概念是通用的,而很多这种概念被流行的程序设计语言所广泛支持。
|
||
|
||
声明(declaration)将名字引入作用域,其作用是:一是为命名实体指定一个类型;二(可选)是进行初始化。大致来说,一个声明定义了一些功能的使用方式,也就是,定义了函数、变量或类的接口。如果一个声明给出了声明实体的完整描述的话,我们称之为定义(definition)。定义是声明,但声明不是定义。这两者的区别反映出“如何使用一个实体(接口)”与“这个实体如何完成它应该做的事情”之间的根本区别。
|
||
|
||
很多愚蠢的错误都是在很忙或疲倦的时候发生的。
|
||
|
||
C++不允许我们对内置类型设置默认初始化功能,全局变量会被默认初始化为0,但应少使用全局变量。最常使用的变量--局部变量和类成员--是不会被初始化的,除非你对它进行初始化。
|
||
|
||
一个变量的作用域越大,名字就应该越长,越有描述性。
|
||
|
||
?:结构称作算术if(arithmetic if )或条件表达式(conditional expression)
|
||
|
||
形式参数:formal argument;参数:parameter
|
||
|
||
在函数声明中,形参的名字不是必需的,只是对于编写好的注释很有益处。
|
||
|
||
参数使用的基本原则:
|
||
\begin{itemize}
|
||
\item 使用传值方式传递非常小的对象
|
||
\item 使用传常量引用方式传递不需修改的大对象
|
||
\item 让函数返回一个值,而不是修改通过引用参数传递来的对象
|
||
\item 只有迫不得已时才使用传引用方式
|
||
\end{itemize}
|
||
|
||
实际参数:actual argument
|
||
|
||
尽量作用显示转换:\verb|static_cast<int>(x)|
|
||
|
||
当一个函数被调用时,编译器分配一个数据结构,保存所有参数和局部变量的拷贝,这样的数据结构称为函数活动记录(function activation record),每个函数的活动记录都有自己特有的详细布局。
|
||
|
||
递归(recursive)
|
||
|
||
活动记录栈(stack of activation record);调用栈(call stack)
|
||
|
||
一个constexpr函数和普通函数行为相同,但若在需要一个常量的位置处使用它,则有所不同,此时若传递的参数是常量表达式,则计算在编译时完成。为使该机制可行,要求constexpr函数必须非常简单。在C++11中,函数体只有包含一条return 语句;在C++14中,还可以写简单的循环语句。
|
||
|
||
一段代码中,创建变量的顺序与销毁的顺序相反。
|
||
|
||
\textcolor{red}{\verb|v[++i]=i|}是有很大的问题:不同的编译器不一定给出警告,不同的优化方法产生的结果可能不同,不能保证赋值符左边的子表达式一定先于右边的计算。
|
||
\begin{verbatim}
|
||
//file1
|
||
int x1 = 1;
|
||
int y1 = x1+2
|
||
|
||
//file2
|
||
extern int y1;
|
||
int y2 = y1 + 2;
|
||
\end{verbatim}
|
||
这段代码的问题是:使用了全局变量;全局变量名字太短;全局变量使用了复杂的初始化。\par
|
||
\begin{verbatim}
|
||
const Data& default_date()
|
||
{
|
||
static const Deat dd(1970,1,2);
|
||
}
|
||
\end{verbatim}
|
||
一个静态的局部变量只在首次调用时才被初始化;使用引用,消除了不必要的对象拷贝;使用常量引用,可以防止调用者无意中改变对象的值。
|
||
|
||
|
||
|
||
\section{编码错误}
|
||
\begin{verbatim}
|
||
double my_abs(int x)
|
||
{
|
||
if (x < 0)
|
||
return -x;
|
||
else if (x > 0)
|
||
return x;
|
||
}
|
||
\end{verbatim}
|
||
这种情况下,当$x=0$会返回无效值
|
||
|
||
Program to an interface, not an implementation.
|
||
|
||
Favor object composition over class inheritance.
|
||
|
||
There are important differences between these techniques. Object composition lets you change the behavior being composed at run-time,but it also requires indirection and can be less efficient. Inheritance lets you provide default implementations for operations and lets subclasses override them. Parameterized types let you change the types that a class can use. But neither inheritance nor parameterized types can change at run-time. Which approach is best depends on your design and implementation constraints.
|
||
|
||
|
||
|
||
\end{document}
|