C++讲义 第二章 变量和基本类型 wchar_t 在字符字面前加L就能够得到wchar_t类型的宽字符字面值
const const 限定符把一个对象转化为一个常量 1 const int bufSize = 512 ;
任何修改bufSize的尝试都会导致编译错误i,定义时必须初始化。
const默认为文件的局部变量 1 2 3 4 5 6 int counter;extern int count;++counter;
除特别声明,在全局作用域声明的const变量是定义该对象文件的局部变量,不能被别的文件访问。
1 2 3 4 5 6 extern const int bufSize = fcn ();extern const int bufSize; a = bufSize;
引用 引用就是对象的另一个名字,在实际程序中主要用作函数的形式参数。
引用是一种复合类型,在变量名前“&”来定义,不能定义引用类型的引用,但是能定义任何其他类型的引用
1 2 3 4 int ival = 1024 ;int &refVal = ival; int &refVa2; int &refVa3 = 10 ;
const 引用 const引用是指向const对象的引用:
1 2 3 const int ival = 1024 ;const int &refVal = ival;int &ref2 = ival;
可以读取但是不可以修改refVal,因此对refVal的赋值都是不合法的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 #include <iostream> int main () {int i, &ri = i;i = 5 ; ri = 10 ; std::cout << i << " " << ri << std::endl; return 0 ; } ``` > 52 页</iostream> const 引用可以初始化为不同类型的的对象或者初始化为右值```c int i = 1024 ;const int &r = 1024 ;const int &r2 = r + i;</code></pre> <h2>第三章 标准库类型</h2> <h3>标准string类型</h3> string类型支持长度可变的字符串 string s1 (n,'c' ) <blockquote> 由于历史原因以及为了与C语言兼容,字符串字面值与标准库string类型不是同一类型。 </blockquote> <pre><code class ="c" >int main () {string line; while (getline (cin,line))cout << line << endl; return 0 ; vector是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。 一个容器中所有对象必须是同一种类型的 - `vector<int > ivec;` 和其他变量定义一样,定义vector对象要指定类型和一个变量列表(int 类型对象vector 变量名为ivec) - `vector<T> v (n,i)` v包含n个值为i的元素 - `vector<int > fvec (10 )` ### vector 对象的操作 - v.empty () - v.size () - v.push_back (t) 大家认为vector的下标操作可以添加元素,以下是错误 ```c vector<int > ivec for (vector<int >::size_type ix=0 ;ix=0 ;ix != 10 ; ++ix) ivec[ix] = ix;```</int ></int > 但是ivec是vector对象,而且下标只能用于获取已存在的元素 正确写法: ```c for (vector<int >::size_type ix=0 ;ix!=10 ;++ix)ivec.push_back (ix); ```</int > > `const char *`与`char const *`效果一样,都是不允许修改指针指向的地址空间的值,即把值作为常量,而`char * const `则是不允许修改指针自身,不能再指向其他地方,把指针自己当作常量使用。需要注意的是,使用`char * const `定一个常量指针的时候一定记得赋初始值,否则再其他地方就没法赋值了。 ```c #include <iostream> using std::cout;using std::endl;</iostream>int main () {const char *st = "The expense of spirit\n" ;int len = 0 ;while (*st) { ++len; ++st; }cout << len << ": " << st << endl; return 0 ;} </code></pre> <pre><code class ="c" >#include <iostream> using std::cout;using std::endl;</iostream>const char *st = "The expense of spirit\n" ;int main () {int len = 0 ;const char *p = st;while (*p) { ++len; ++p; }cout << len << ": " << st << endl; return 0 ;} </code></pre> <pre><code class ="c" >#include <string> using std::string;#include <iostream> using std::cout; using std::endl;</iostream></string>int main () {string substr = "Hello" ; string phrase = "Hello World" ; string slang = "Hiya" ; if (substr < phrase) cout << "substr is smaller" << endl; if (slang > substr) cout << "slang is greater" << endl; if (slang > phrase) cout << "slang is greater" << endl;return 0 ;} </code></pre> <pre><code class ="c" >#include <iostream> #include <vector> </vector> </iostream> using std::cout;using std::endl;using std::vector;int main () {vector<int > ivec; int val;for (vector<int >::size_type ix = 0 ;ix != 10 ; ++ix) ivec.push_back (ix);</int ></int > cout << "ivec.size: " << ivec.size () << endl; for (vector<int >::size_type ix = 0 ; ix != ivec.size (); ++ix)ivec[ix] = 0 ;</int > if (ivec.empty () == false ) {cout << "vector contents: " << endl; for (vector<int >::size_type ix = 0 ;ix != ivec.size (); ++ix) cout << ivec[ix] << endl; } return 0 ;} ```</int > ```c #include <vector> #include <string> #include <iostream> </iostream> </string> </vector> using std::vector;using std::string;using std::cin;using std::cout;using std::endl;int main () {vector<int > ivec (10 ) ;</int >for (vector<int >::size_type ix = 0 ; ix != ivec.size (); ++ix)ivec[ix] = 0 ;</int > for (vector<int >::size_type ix = 0 ; ix != ivec.size (); ++ix)cout << ivec[ix] << " " ; cout << endl;</int > for (vector<int >::iterator iter = ivec.begin ();iter != ivec.end (); ++iter) *iter = 0 ; for (vector<int >::iterator iter = ivec.begin ();iter != ivec.end (); ++iter) cout << *iter << " " ; cout << endl;</int > vector<int >::iterator iter = ivec.begin (); while (iter != ivec.end ()) {*iter = 0 ; ++iter; } return 0 ;} ```</int > ## 迭代器 > P84 除了使用下标来访问vector对象的元素外,标准库还提供了另外一种访问元素的方法。迭代器是一种检查容器内元素并遍历元素的数据类型。 1. 容器的iterator类型vector<int >::iterator iter; 2. begin和end操作end操作返回的迭代器并不指向vector中的任何实际元素,哨兵的作用。 3. 应用程序示例```c for (vector<int >::iterator iter = ivec.begin();iter !=ivec.end(); ++iter) *iter = 0 ;```</int > 4. const_iterator该类型只能用于读取容器内的元素,但不能修改他的值。 与const iteator的区别: 使用const_iterator类型时,得到一个迭代器,自身值是可以改变的,但不能用来改变其所指向的元素的值(可以自增但不能赋值) const 的迭代器必须初始化迭代器,初始化后不能改变。```c vector<int > nums (10 ) ;const vector <int >::iterator cit = nums.begin ();*cit =1 ; ++cit; ```</int ></int > const 迭代器几乎没什么用,一旦初始化后只能用它来改写其指向的元素但不能指向别的元素。## bitset > P88 - `bitset<32 > bitvec` 初始化32 位,每位都是0 - `bitset<n> b (u)` b是unsigned long 类型的一个副本 - `bitset<n> b (s)` - `bitset b (s,pos,n) ` b是s中从位置pos开始的n个位副本 - `string strval ("1100" ) ` - `bitset < ;32 > bitset4 (strval)` 高阶置0 ,反向转化的- `b.any ()` - `b.none ()` - `b.count ()` - `b.size ()` - `b[pos]` - `b.set ()` `b.set (pos)` - `b.reset ()` - `b.flip ()` ```c #include <cstddef> #include <iostream> #include <string> using std::cout;using std::endl;using std::string;using std::size_t ;#include <bitset> using std::bitset;int main () {bitset<32 > bitvec; bool is_set = bitvec.any (); bool is_not_set = bitvec.none (); cout << "bitvec: " << bitvec << endl; size_t sz = bitvec.size (); size_t bits_set = bitvec.count (); for (int index = 0 ; index != 32 ; index += 2 )bitvec[index] = 1 ; for (int index = 0 ; index != 32 ; index += 2 )bitvec.set (index); unsigned i;cout << "bitvec: positions turned on:\n\t" ; for (int index = 0 ; index != 32 ; ++index)if (bitvec[index])cout << index << " " ; cout << endl; bitvec.reset (0 ); bitvec[0 ] = 0 ; bitvec.reset (); bitvec.set (); bitvec.flip (0 ); bitvec[0 ].flip (); bitvec.flip (); bitvec = ~bitvec; bitset<16 > bitvec1 (0xffff ); bitset<32 > bitvec2 (0xffff ); bitset<128 > bitvec3 (0xffff ); cout << "bitvec1: " << bitvec1 << endl; cout << "bitvec2: " << bitvec2 << endl; cout << "bitvec2[0] " << bitvec2[0 ] << endl; cout << "bitvec2[31] " << bitvec2[31 ] << endl; cout << "bitvec3: " << bitvec3 << endl; string strval ("1100" ) ;bitset<32 > bitvec4 (strval); cout << "strval: " << strval << endl; cout << "bitvec4: " << bitvec4 << endl; { string str ("1111111000000011001101" ) ;bitset<32 > bitvec5 (str, 5 , 4 ); bitset<32 > bitvec6 (str, str.size () - 4 ); cout << "str: " << str << endl; cout << "bitvec5: " << bitvec5 << endl; cout << "str: " << str << endl; cout << "bitvec6: " << bitvec6 << endl; } { unsigned long ulong = bitvec3.to_ulong ();cout << "ulong = " << ulong << endl; } bitset<32 > bitvec7 = bitvec2 & bitvec4; cout << "bitvec7: " << bitvec7 << endl; bitset<32 > bitvec8 = bitvec2 | bitvec4; cout << "bitvec8: " << bitvec8 << endl; cout << "bitvec2: " << bitvec2 << endl; return 0 ;}
第四章 数组和指针 指针的定义和初始化 string*
错误的理解成一种数据类型
string* ps1,ps2
实际上是ps1是指针,ps2是一个普通的string对象
未初始化的指针是无效的,直到给该指针赋值后,才能使用它
赋值操作的约束 int型变量赋值给指针式非法的,尽管这个int型变量的值可能是0,允许把数值0或在编译时可获得0值的const量赋值给指针
1 2 3 4 5 6 7 int ival;int zero = 0 ;const int c_ival = 0 ;int *pi = ival;(×)pi = zero;(×) pi = c_ival; pi = 0 ;
从C继承下来的预处理变量:
void*
指针C++ 提供了一种特殊的指针类型 void*
,它可以保存任何类型对象的地址:
1 2 3 4 double obj = 3.14 ;double *pd = &obj;void *pv = &obj;pv = pd;
void*
指针只支持几种有限的操作:与另一个指针进行比较;向函数传递void*
指针或从函数返回 void*
指针;给另一个 void*
指针赋值。
不允许使用void*
指针操纵它所指向的对象。
指针操作 指针和引用的比较 第一个区别在于引用总是指向某个对象:定义引用时没有初始化是错误的。第二个重要区别则是赋值行为的差异:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化,就始终指向同一个特定对象。
指针和const限定符 介绍了指针和 const 限定符之间的两种交互类型:指向 const对象的指针和 const 指针。
指向const 对象的指针 我们使用指针来修改其所指对象的值。但是如果指针指向const 对象,则不允许用指针来改变其所指的 const 值。
为了保证这个特性,C++ 语言强制要求指向 const 对象的指针也必须具有 const 特性:
这里的 cptr 是一个指向 double 类型 const 对象的指针,const 限定了cptr 指针所指向的对象类型,而并非 cptr 本身。也就是说,cptr 本身并不是const。在定义时不需要对它进行初始化,如果需要的话,允许给 cptr 重新赋值,使其指向另一个 const 对象。但不能通过 cptr 修改其所指对象的值:
不能使用 void* 指针保存 const 对象的地址,而必须使用 const void* 类型的指针保存 const 对象的地址:
1 2 3 const int universe = 42 ;const void *cpv = &universe; void *pv = &universe;
允许把非 const 对象的地址赋给指向 const 对象的指针,例如:
1 2 double dval = 3.14 ;cptr = &dval;
但是同样必须遵循不能通过cptr修改对象的值
const指针 const指针指的是指针本身的值不能改变
指向const对象的const指针 1 2 const double pi = 3.14159 ;const double *const pi_ptr = π
既不能修改 pi_ptr 所指向对象的值,也不允许修改该指针的指向。
指针和 typedef (讨论) 下面是一个几乎所有人刚开始时都会答错的问题。假设给出以下语句:
1 2 typedef string *pstring;const pstring cstr;
请问 cstr 变量是什么类型?
简单的回答是 const pstring
类型的指针。
进一步问:const pstring
指针所表示的真实类型是什么?很多人都认为真正的类型是:
也就是说,const pstring 是一种指针,指向 string 类型的 const 对象,但这是错误的。
错误的原因在于将 typedef 当做文本扩展了。声明 const pstring 时,const 修饰的是 pstring 的类型,这是一个指针。因此,该声明语句应该是把cstr 定义为指向 string 类型对象的 const 指针,这个定义等价于:
创建动态数组 每一个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区或堆。
const 对象的动态数组 如果我们在自由存储区中创建的数组存储了内置类型的 const 对象,则必须为这个数组提供初始化:因为数组元素都是 const 对象,无法赋值。实现这个要求的唯一方法是对数组做值初始化:
1 2 const int *pci_bad = new const int [100 ];(×)const int *pci_ok = new const int [100 ]();(√)
C++ 允许定义类类型的 const 数组,但该类类型必须提供默认构造函数:
1 const string *pcs = new const string[100 ];
已创建的常量元素不允许修改――因此这样的数组实际上用处不大。
第五章 表达式 箭头操作符
const对象的动态分配和回收 1 const int *pci = new const int (1024 );
与其他常量一样,动态创建的const对象必须在创建时初始化,并且一经初始化,其值就不能修改。
对于类类型的const动态对象,如果该类提供了默认构造函数,则此类可以隐身初始化,但是内置类型对象以及未提供默认构造函数的类类型对象必须显示初始化。
有符号与无符号类型之间的转换 如果int
类型足够表示所有的unsigned short
型的值,则将unsigned short
转换为int
,否则将这两个操作数转换为 unsigned int
.
同理 unsigned int
和long
转换为unsigned long
.