C++学习

目录

C++ Learning

基础知识

函数

const

static在类中

this指针

enum枚举

抽象类

友元类

虚继承

智能指针

四种cast转换

inline 内联函数

lambda表达式

进阶知识

静态库与动态库

C++右值引用和std::move

代码练习

STL

基础知识

源码分析

基础:模板——特化,泛化

分配器

设计模式

单例模式(Singleton)

适配器(Adapter)

面试问题

构造一个不能被继承的类:

i++是不是原子操作:

附 录

重载[ ]运算符

自增运算符

基本类型操作符重载

重载( )运算符

函数模板

单线程单例

单例—饿汉

多线程单例

多线程单例—DCL

单例读写乱序—1

单例读写乱序—2

单例读写乱序—3

单例模式—原子操作

左右值引用

实现移动语义

shared_ptr


C++ Learning

基础知识

函数

  • (1)没有规定运算顺序

    • cout << i << " " << ++i << endl;  //  可能 0 1 也可能 1 1 但我测试是 0 1,解释为<<没有规定运算顺序
      int i = f() * g();  // 可能先计算f(),也可能先计算g()
  • (2)传递数组

    • // 传递数组参数的三种方式
      //  1. 标记指定长度
      void print(const char *cp) { if (cp) while (*cp) cout << *cp++; }  // 以0结尾
      //  2. 使用标准库的规范
      int j[2] = {1, 2};
      void print(const int *beg, const int *end) { while (beg != end) cout << *beg++ << endl; }
      print(begin(j), end(j)); end实现:https://www.cnblogs.com/yuanyb/p/11402831.html
      //  3. 显示传递数组大小的形参
      void print(const int ia[], size_t size) { ... } 
      print(j, end(j) - begin(j));
      // 数组引用形参
      void print(int (&arr) [10])  // 必须传递10个整数的数组,其余的不行。 (&arr)括号不能去掉,去掉之后,&arr[10]是引用的数组,是数组;原来是10个整数的整形数组的引用,是引用。
      // 该引用参数绑定到对应的实参上,也就是绑定到数组上,数组的大小是构成数组类型的一部分,所以被绑定的实参数组必须要是10个整数的数组。
      // 题目:下面代码存在问题
      void print(const int ia[10])
      {
          for (size_t i = 0; i != 10; ++i)
              cout << ia[i] << endl;
          // 数组上写着数组大小是10,但是实际上,传输过来的不一定是10,而循环写了10,可能会越界。
          // 而想要传递数组大小为10的数组引用,必须 const int (&ia) [10],记住传递数组引用。
      }
  • (3)返回值

    • // 1. 返回值 与 参数传递 类似,值传递都会拷贝,引用传递则不拷贝。
      // 2. 返回值 不要 引用 或者 指针指向 函数内的局部变量。
      // 3. 引用返回左值
      char& get_val(string &str, string::size_type idx) { return str[idx]; }
      string s("a value");
      get_val(s, 0) = 'A';  // 可以正确使用
      cout << s << endl; // A value
  • (4)返回数组指针

    • // 定义返回数组的指针或引用的函数比较繁琐,具体采取措施如下
      // 1. 使用类型别名
      typedef int arrT[10];  // arrT表示的是一个含有10个整数的数组
      using arrT = int[10];  
      arrT* func(int i);     // func返回一个指向含有10个整数数组的指针
      // 2. 声明一个返回数组指针的函数
      // 在此之前,回顾一下:
      int arr[10];   // arr是一个含有10个整数的数组
      int *p1[10];   // p1是一个含有10个整数指针的数组
      //  可见,数组的优先级 [] 高于 指针的优先级 *
      int (*p2)[10] = &arr;  // p2是一个指针,指向10个整数的数组。
      // 正题:
      int (*func(int i)) [10];   // 返回数组指针的函数
      // 解释:
          func(int i );            // 表示一个传int类型的函数
          (*func(int i));          // 表示我们可以对返回值解引用
          (*func(int i)) [10];     // 表示解引用func的调用将得到一个大小是10的数组
          int (*func(int i)) [10]; // 表示数组中的元素是int类型
      // 3. 使用尾置返回类型
      auto func(int i) -> int(*)[]; // 为了表示使用位置返回类型,在原本放放回类型的地方放入auto,然后再在参数列表后面使用 -> + 返回类型。
      // 4. 使用decltype : 仅在知道返回的指针会指向哪个可能的数组
      int odd [] = {1,3,5,7,9};
      int even [] = {2,4,6,8,10};
      decltype(odd) *arrPtr(int i) { return (i % 2) ? &odd : & even; } // 返回一个指向数组的指针。
      // 需要注意的是,decltype并不负责把数组类型转换成对应的指针,所以最后还需要加上*

const

  • (1)在函数重载中

    • // 形参加顶层const,将被忽略 —— 出自 C++ primer 191
      void fcn(int i) {}
      void fcn(const int i) {} 
      // 以上两个函数的将出现重复定义的错误
      ​
      // 函数加const,由于函数签名不一致,不会导致重复定义的问题
      void fcn(int i) {}
      void fcn(int i) const {}

static在类中

  • (1)可以修饰成员变量,成员函数 和 类本身。

    • (1-1)修饰类本身,与修饰普通变量一致。

    • (1-2)修饰成员变量,可以分private与public,若不使用,应该不分配空间,若要使用,必须先进行初始化(定义);初始化过程:在类外(全局区,函数内不行)定义,([类型] 类名称:: 静态变量名 = ...) ,无论是private还是public都可以这样定义,但是访问的时候,类外只能访问public的静态变量。

    • (1-3)修饰成员函数,则成为静态成员函数,不能访问类的非静态成员(变量+函数)。

this指针

  • https://light-city.club/sc/basic_content/this/

  • 基本认识:

    • (1)一个对象的this指针并不属于对象自身的一部分,即,对sizeof(对象)没有影响。

    • (2)类的非静态成员函数执行时,this指针将作为隐含形参,指向对象的地址,对类数据成员的访问全部都是通过this指针进行。

  • 使用方法:

    • (1)在类的非静态成员函数返回对象本身时,直接使用 return *this。

    • (2)当参数名与成员数据名相同时,this -> n = n,不能写成 n = n 。

  • this的类型:

    • (1)普通成员函数:A * const this,详细见网址。

    • (2)const成员函数:const A * const this,因为const成员函数只能访问const变量和const函数。注:案列中,成员变量 int age;直接使用 this->age被const函数使用。

enum枚举

  • 传统做法问题:

    • 作用域不受限,容易引起命名冲突。

      • enum color {RED, BLUE};
        enum feeling {EXCITED, BLUE};
        // BLUE 导致无法通过编译
    • 会隐式转换成int。

    • 表征枚举变量的实际类型不能明确指定,无法支持枚举类型的前向声明。

  • 经典做法:

    • 加前缀 COLOR_BLUE、FEELING_BLUE,或者使用命名空间:

      • namespace Color { enum Type {RED = 15, BLUE, YELLOW}; };
        // 调用: 1. Color::Type c = Color::BLUE
        // 2. using namespace Color; Type c = BLUE
    • 结构体限定:

      • struct Color { enum Type{RED = 102, YELLOW, BLUE}; };
        // 调用:1. Color c; cout << c.RED << endl; --> 102
        // 2. Color::Type c = Color::BLUE; cout << c << endl; --> 104 
    • C++11的枚举类 (未完)

      • 新的enum作用域不在全局。

      • 不能隐式转换成其他类型。

抽象类

  • 基本认识:

    • (1)存在纯虚函数,通过使用vitrual定义成员函数,并赋值为0。

    • (2)不能创建对象。

  • 进阶认识:

    • (1)派生类若没有完全覆盖纯虚函数,则派生类也是抽象类,对应基本认识(1)。

    • (2)成员函数可以调用纯虚函数,但构造和析构函数不可以。

    • (3)纯虚函数可以有自己的构造和析构函数。

友元类

  • 基本认识:

    • (1)友元提供了一种访问类 私有 或者 保护 成员的机制。

      • (1-1)友元函数:普通函数访问某个类中的私有或者保护成员。

      • (1-2)友元类:类A中的成员函数访问类B中的私有或者保护成员。

    • (2)友元关系单向性,如下例,B是A的友元,但是A不是B的友元,即无法访问B的私有与保护成员。

    • (3)友元关系没有继承性,如下例,若再有C继承A,B无法直接访问C的私有或保护成员。

    • (4)友元关系没有传递性,如下例,若再有C是B的友元,友元类C无法直接访问A的私有与保护成员。但是还是可以访问:

      • #include <iostream>
        using namespace std;
        class A{
        public:
            A(int _a):a(_a){};
            friend class B;
        private:
            int a;
        };
        class B{
        private:
            int getb(A ca) {
                return  ca.a; 
            };
            friend class C;
        };
        class C {
        public:
            int getc(B b, A a) {
                return b.getb(a);
            }
        };
        int main() {
            A a(3);
            B b;
            C c;
            cout<<c.getc(b, a)<<endl;
            return 0;
        }
  • 使用方式:

    • (1)类中任何区域声明,类外部定义。

      • // 友元函数
        class A { int age; friend int GetAge(A &a); }
        int GetAge(A &a) { return a.age; }
        // 友元类
        class A {int age; friend class B; }
        class B {int GetAge(A a) {return a.age;} }
        A a(3); B b; b.GetAge(a);

虚继承

  • 基本认识:

    • (1)多继承,常见为菱形继承,会导致最终派生类的命名冲突和数据冗余。

      • class A { int a; };
        class B : public A {int b; }; 
        class C : public A {int c; };
        class D : public B, public C {int d; };
        // D 拥有两份a, 使用a赋值时,需要指明从哪条路径上来的,例如 B::a,否则产生二义性
    • (2)虚继承常见于多继承关系,用于防止最终派生类拥有多份基类数据。

    • (3)一个派生类定义虚继承,表示它承诺共享自己的基类,被共享的基类成为虚基类。

      • class A { int a; };
        class B : virtual public A {int b; };  // 定义虚继承的是 中间派生类
        class C : virtual public A {int c; };  // 定义虚继承的是 中间派生类
        class D : public B, public C {int d; };
    • (4)即便使用虚继承,也仍会出现二义性:

      • class A { int a; int x; };
        class B : virtual public A {int b; int x; }; 
        class C : virtual public A {int c; }; 
        class D : public B, public C {int d; Get(x)};
        // D直接访问x,将访问B的x,若B没有x,则访问A的x
        // 若C也有x,则出现二义性
    • (5)构造顺序从最低的虚基类开始。

智能指针

  • 基本认识:

    • (1)智能指针主要用于管理堆上的内存分配。

    • (2)它将普通指针封装成栈对象,当程序执行超过栈对象作用域时,会调用析构函数,释放申请的堆内存。

  • 类型:

    • (1)auto_ptr

    • (2)unique_ptr

      • (2-1)独占式,同一时间只允许有一个智能指针可以指向对象。

      • (2-2)使用std::move可以转移对象的所有权。

    • (3)shared_ptr

      • (3-1)有一个引用计数,use_count(),只有当引用计数为0时,程序才会释放对象内存。

      • (3-2)make_shared 返回一个shared_ptr指针。

      • (3-3)还是会引起内存泄露。

        • (3-3-1)将shared_ptr放入容器中,后续可能不需要某些元素,必须使用erase删除那部分元素。

        • (3-3-2)两个shared_ptr指针A,B,各自指向一个内存NEW_A,NEW_B,而内存NEW_A中存在一个指向NEW_B的指针C,内存NEW_B中存在一个指向NEW_A的指针D。此时,NEW_A、NEW_B的引用计数都是2。在A、B生命周期结束时断开A->NEW_A的引用,B->NEW_B的引用,但是因为引用计数不为0,无法调用A,B的析构函数,导致指针C\D存在,无法释放内存;解决方法:将C或者D换成weak_ptr即可。

      • // 使用方式,make_shared返回shared_ptr,赋值拷贝函数
        shared_ptr<T> i_pt
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: PCL (Point Cloud Library) 是一个非常强大的点云处理库,它提供了丰富的功能来处理、分析和可视化点云数据。下面将从学习教程的角度来介绍PCL C++ 学习教程。 在学习PCL C++学习教程之前,我们先了解一下PCL的基础知识。PCL是一个开源项目,可以在Windows、Linux和Mac OS等操作系统上使用。它提供了常见的点云数据类型、滤波、分割、配准、特征提取和重建等功能。此外,PCL还有一个强大的可视化模块,可以方便地实时显示点云数据。 对于初学者而言,可以从PCL官方网站上的教程入手。官方网站提供了完整的文档和示例代码,可供学习者参考。此外,还有一些博客和视频教程可以帮助学习者更好地掌握PCL的使用。 学习PCL C++,需要一定的编程基础知识,例如掌握C++语言、面向对象编程和基本的算法理论等。在学习过程中,可以按照如下步骤进行: 1. 安装PCL库:根据自己的操作系统选择合适的安装方式,到PCL官方网站下载安装包并按照指南进行安装。 2. 学习PCL的基础知识:首先熟悉PCL的常见数据类型,例如点云表示和常见的PCL数据结构。然后学习如何读取和保存点云数据,以及基本的点云操作和可视化。 3. 学习PCL的模块功能:PCL库包含多个模块,例如滤波、分割、配准、特征提取和三维重建等。可以针对自己的需求选择相应的模块进行学习,并掌握它们的基本原理和使用方法。 4. 练习和实践:通过完成一些PCL的实际项目,例如点云配准、目标检测或三维重建等,来巩固所学的知识。 总之,学习PCL C++需要一定的时间和耐心,通过实践和不断学习,逐渐掌握PCL的使用技巧。希望以上简要的回答能对你理解PCL C++学习教程有所帮助。 ### 回答2: PCL(Point Cloud Library)是一个开源的计算机视觉库,主要用于处理和分析点云数据。它提供了许多功能强大的算法和工具,可以帮助开发人员在点云处理方面进行快速开发。 PCL C学习教程是PCL官方提供的一份入门教程,旨在帮助初学者快速上手PCL C的开发。该教程主要介绍了PCL的基本概念和使用方法,并提供了一些常见的点云处理算法的示例代码。通过学习PCL C学习教程,我们可以了解PCL的基本功能和使用技巧,并且可以开始进行简单的点云处理任务。 在学习PCL C的过程中,我们需要掌握一些基础知识,比如点云的表示和存储方式、点云的滤波和分割方法、点云的特征提取和匹配算法等等。PCL C学习教程提供了详细的解释和示例代码,以帮助我们理解和运用这些基础知识。 此外,PCL C学习教程还介绍了一些常见的点云处理应用场景,比如目标检测、点云配准和重建等。通过学习这些应用场景,我们可以了解到PCL C在不同领域的应用和相关的算法思想。 总结来说,PCL C学习教程是学习和使用PCL的入门指南,通过学习教程中的内容,我们可以掌握PCL C的基础知识和技能,并且开始进行简单的点云处理任务。 ### 回答3: PCL(Point Cloud Library)是一个用于点云数据处理的开源库。学习PCL可以帮助我们更好地理解和处理点云数据,从而在计算机视觉、机器人领域等方面开展相关工作。 学习PCL可以从以下几个方面入手。首先,了解PCL的基本概念和原理是非常重要的。PCL涵盖了点云数据获取、滤波、特征提取、配准等算法,了解这些基本概念是进行更高级别的数据处理的基础。 其次,学习PCL的使用方法。PCL提供了丰富的功能库和示例代码,通过实践使用可以更好地掌握PCL的各项功能。可以通过看官方文档、阅读教程、查阅论坛等方式学习PCL的使用方法。 再次,尝试应用PCL解决实际问题。通过完成一些小项目,如点云数据的滤波、分割、配准等任务,可以锻炼我们对PCL的熟练程度,并将PCL应用于实际工程中。 最后,与其他PCL爱好者交流学习。在互联网上可以找到很多与PCL相关的讨论组、社区和论坛,与其他使用PCL的人交流经验、分享学习心得,可以提高我们的学习效果。 总之,学习PCL需要理解基本概念和原理、掌握使用方法、应用于实践项目以及与他人交流学习。希望以上建议对学习PCL有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值