zoukankan      html  css  js  c++  java
  • C++基础学习(一)

    1. 数据类型

    1.1 基本内置类型

      我们通过下列代码可知电脑上的基本数据类型的大小:

     1 #include<iostream>  
     2 #include<string>  
     3 #include <limits>  
     4 using namespace std;
     5 
     6 int main()
     7 {
     8 
     9     cout << "char: 		" << "所占字节数:" << sizeof(char);
    10     cout << "	最大值:" << (numeric_limits<char>::max)();
    11     cout << "		最小值:" << (numeric_limits<char>::min)() << endl;
    12     
    13     cout << "float: 		" << "所占字节数:" << sizeof(float);
    14     cout << "	最大值:" << (numeric_limits<float>::max)();
    15     cout << "		最小值:" << (numeric_limits<float>::min)() << endl;
    16     
    17     cout << "int: 		" << "所占字节数:" << sizeof(int);
    18     cout << "	最大值:" << (numeric_limits<int>::max)();
    19     cout << "	最小值:" << (numeric_limits<int>::min)() << endl;
    20     
    21     cout << "unsigned: 	" << "所占字节数:" << sizeof(unsigned);
    22     cout << "	最大值:" << (numeric_limits<unsigned>::max)();
    23     cout << "	最小值:" << (numeric_limits<unsigned>::min)() << endl;
    24     
    25     cout << "long: 		" << "所占字节数:" << sizeof(long);
    26     cout << "	最大值:" << (numeric_limits<long>::max)();
    27     cout << "	最小值:" << (numeric_limits<long>::min)() << endl;
    28     
    29     
    30     cout << "double: 	" << "所占字节数:" << sizeof(double);
    31     cout << "	最大值:" << (numeric_limits<double>::max)();
    32     cout << "	最小值:" << (numeric_limits<double>::min)() << endl;
    33     return 0;
    34 }

    1.2 const 和 auto 

    1. const 基本介绍

      const对象一旦创建后其值就不能再改变,所以const对象必须初始化。编译器在编译过程会把用到该变量的地方替换成相应的值,为了执行上述的替换,编译器必须知道变量的初始值。

    1 const int i = get_size();  // 运行时初始化
    2 const int j = 3; // 编译时初始化
    3 const int k;// 错误

      默认情况下,const对象仅在文件中有效。当多个文件中出现了同名的const变量时,其实等同于在不同文件中分别定义了独立的变量。如果想在在文件中得到共享,即在一个文件中定义const,而在其他多个文件中声明并使用它。可以使用 extern 关键词,对于const变量不管是声明还是定义都添加 extern 关键词,这样只需定义一次就可以了。

      但是需要注意下面这个例子

     1 struct A {
     2     int* ptr;
     3 };
     4 
     5 int main()
     6 {
     7     int k = 5, r = 6;
     8     const A a = { &k };// const声明的变量必须初始化
     9     a.ptr = &r; // !error
    10     *a.ptr = 7; // no error
    11 }

      可以看到,const 修饰 a 之后其实要求的是 ptr (存储一个地址)不能变,但其实可以改变 *ptr—— c++ 保持物理常量行不变,逻辑常量性不保证。

    2. 类中的const变量

     1 struct A {
     2     const int i; // 构造类是初始化。非静态
     3 };
     4 
     5 struct B {
     6     static const int i;// 静态
     7 };
     8 
     9 const int B::i = 3; // 常在类中中直接声明
    10 
    11 int main()
    12 {
    13     A bf = { 1 };
    14  
    15 }

    3. 顶/底层 const  和 auto

      下面是顶层 const 和 底层 const 的实例:

     1 /*
     2  3     顶层const:指针本身是个常量
     4     底层const:指针所指的对象是一个常量
     5     
     6  7     auto一般会忽略顶层const,会保留底层const
     8 */
     9 
    10 #include"iostream"
    11 using namespace std;
    12 int main()
    13 {
    14     const int i = 19; //i值不能改变,顶层const
    15     const int *p = &i;//p值可以改变,底层const(*P值不能改变->指针所指的对象是个常量)
    16     
    17     int z = 18;
    18     int *const o = &z;//o值不能改变,顶层const
    19     int t = 13;
    20     //o = &t; //错误,因为o是顶层,o值不能改变
    21 
    22     //打印类型
    23     cout << typeid(i).name() << endl;//int
    24     cout << typeid(p).name() << endl;//int const *
    25     cout << typeid(*p).name() << endl;//int 
    26     cout << typeid(o).name() << endl << endl;// int *
    27 
    28     auto a = o;
    29     int y = 12;
    30     a = &y; // a值可改变,说明忽略了o的顶层const。对比第20行的o
    31     cout << "*a=" << *a << "	 a类型" << typeid(a).name()<< endl;
    32 
    33     auto b = p;
    34     b = &y; //p是底层const,b也是底层const,b值可改变,但是*b不能改变
    35     //*b = 9; //报错,b是底层const,b指针所指的对象不能改变。---》说明auto保留了底层const
    36     cout << "*b=" << *b << "	 b类型" << typeid(b).name() << endl;
    37 
    38 
    39     return 0;
    40 }

     4. const 修饰函数

      const 可以修饰类返回值(一般用于类返回值是指针的形式。修饰返回值的函数没有意义)。也可以写在函数后(如第7行),标是允许修改类的成员变量(mutable关键字修饰的成员变量除外).

     1 struct A {
     2     int i;
     3     mutable int j;
     4 
     5     void f() const{
     6         //this->i++;// error, const 修饰的函数不能改变类成员变量。
     7         this->j++;// 除非是使用mutable关键字
     8     }
     9 
    10     const int* g() {  
    11         int k = 2;
    12         return &k;
    13     }
    14 
    15     int *const h() {  
    16         int k = 2;
    17         return &k;
    18     }
    19 
    20 };
    21 
    22 int main()
    23 {
    24     A a = { 1 , 2};
    25     a.f();
    26 
    27     /*
    28         a.g() 返回的是 const int *k 类型。是底层const, *k 不能改变
    29     */
    30     const int* k = a.g();
    31     //*k = 3; // 非法
    32     k = new int();// 合法
    33 
    34 
    35     /*
    36         a.h() 返回的是  int *const b 类型。是顶层const, b 不能改变
    37     */
    38     int* const b = a.h();
    39     *b = 3; // 合法
    40     //b = new int();// 非法
    41 }

      

    2. vector 类型

    2.1 vector 基本操作

    • v.empty() 
    • v.size()  返回 vector 对象中元素个数,返回值类型由 vector 定义的 size_type 决定 (vector<int>::size_type)
    • v[n] 返回 v 中第 n 个位置上元素的引用
    • v1 = v2 用 v2 中元素的拷贝替换 v1 中的元素
    • v1 == v2 当且仅当元素数量 and 元素值相同

    2.2 访问 vector 

    • 可以通过下标形式访问 vector,但是不能通过下标形式添加元素而是,push_back()
    • 使用 range-base-for 或者 iterator 遍历
     1 #include<iostream>
     2 #include<vector>
     3 #include<typeinfo>
     4 
     5 int main() {
     6     std::vector<std::string> v1{ "Tom","Jack","Michael" };
     7     std::vector<int> v2(5, 7);
     8     
     9     for (auto& i : v1) {
    10         std::cout << i << std::endl;
    11     }
    12     
    13     std::cout << "====================" << std::endl;
    14 
    15     for (auto k = v2.begin(); k != v2.end(); ++k) {
    16         std::cout << *k << std::endl;
    17     }
    18 
    19     std::cout << "====================" << std::endl;
    20     
    21     v1.push_back("good dog");
    22     std::vector<std::string>::iterator iter = v1.begin();
    23     for (; iter != v1.end(); ++iter) {
    24         std::cout << *iter << std::endl;
    25     }
    26     
    27     std::cout << "====================" << std::endl;
    28     
    29     v2[0] = 9;
    30     for (decltype(v2.size()) i = 0; i < v2.size(); ++i) {  // v2.size() 返回的是无符号数(>=0),可以用 int,但需要保证不能为负数,否则无符号数会自动合法话。可运行36~38行
    31         std::cout << v2[i] << std::endl;
    32     }
    33 
    34     std::cout << "====================" << std::endl;
    35     // 会输出 “大于”
    36     /*decltype(v2.size()) i = -1;
    37     if( i > 10)
    38         std::cout << "大于" << std::endl;*/ 
    39 
    40 
    41     return 0;
    42 }

    3. 迭代器

    • 我们知道已经可以使用下标运算符来访问 string 对象或 vector 对象的元素(因为只有一些标准库类型有下标运算符,并非全都如此),但是还有一种更通用的机制可以实现——使用迭代器。
    • 如果容器为空,可通过 iter.end() != iter.begin() 来判断,例如:有 string str 对象,则 if (str.end() != str.begin()) {.....} 来保证 str 不为空
    • 凡使用了迭代器的循环体,都不要向迭代器所属容器中添加元素

    3.1 迭代器和指针

      我们可能有疑问,如果是 vector<int> v1 = {1,2,3},那么通过迭代器迭代时,每次的迭代器是 1,2,3 三个数字的地址吗(因为我们可以通过 *iter 来取得数值 )?答案是不是的。

     1 #include<iostream>
     2 #include<vector>
     3 #include<typeinfo>
     4 
     5 int main() {
     6     std::vector<int> v = { 1 ,2,4 };
     7     for (auto& i : v)  
     8         std::cout << typeid(i).name() << &i <<std::endl;
     9     for (auto k = v.cbegin(); k != v.cend(); ++k)  // cbegin()得到const_iterator。begin()得到iterator。如果只进行读操作可用前者
    10         std::cout << typeid(k).name() <<std::endl;
    11     return 0;
    12 }

      我们可以比较 range-based-for 和 iterator-for 的输出类型,其中第八行 &i 输出了 v 中的元素的地址。

      那迭代器到底是啥?此处有解释。

      range based for loop vs regular iterator for loop

      

      

  • 相关阅读:
    Android中SharedPreferences介绍和使用方法
    功能(一):添加影像服务图层
    二、策略模式
    一、简单工厂模式
    C#重点内容之:接口(interface)(一)网络初级示例
    Windows API编程(一)完整的示范程序
    秩序让生活趋向于和谐
    模板专题:类模板
    模板专题:函数模板
    STL之vector详解
  • 原文地址:https://www.cnblogs.com/KongHuZi/p/11188991.html
Copyright © 2011-2022 走看看