现在感觉不会c++有点不靠谱,作为传统的嵌入式出身,只会c语言,不太适应现在的社会情况了,趁着过年有时间,好好补补c++,正式进入面向对象编程。微笑

1.1 hello world

老规矩第一个还是hello world

#include <iostream>
 
/**
    * @brief  创建test对象
    * @param  
    * @retval 
    */ 
    int main(int argc, char **argv)
    {
        std::cout << "hello c++" << std::endl;
        return 0;
    }

c++添加了一个命名空间的概念,cout 和endl都输入std的命令空间,需要在前面加命名空间,也有另一种写法,使用这个命令空间

#include <iostream>
 
using namespace std;

/**
    * @brief  创建test对象
    * @param  
    * @retval 
    */ 
    int main(int argc, char **argv)
    {
        cout << "hello c++" << endl;
        return 0;
    }

这样也可以。
endl是回车的意思,但是这个是可以兼容各个平台的回车。

1.2 自定义命令空间

上一节讲多的std是一个命令空间,这是库默认写的,我们自己也可以自定义命令空间。

#include <iostream>
 
using namespace std;
//这种语法就是自定义命令空间,后面不需要逗号
namespace my_space {
    int haha;
}

/**
    * @brief  创建test对象
    * @param  
    * @retval 
    */ 
    int main(int argc, char **argv)
    {
		//后面使用的时候,跟上节一样,或者直接using namespace my_space;
        cout << "hello c++ " << my_space::haha << endl;

        return 0;
    }

如果有两个变量的名字一样,命令空间不一样的话,需要添加命令空间来区别是哪个变量。

namespace my_space {
    int haha;
}

namespace my_spaceA {
    int haha = 1;
}

using namespace my_space;
using namespace my_spaceA;
/**
    * @brief  创建test对象
    * @param  
    * @retval 
    */ 
    int main(int argc, char **argv)
    {
        cout << "hello c++ " << my_spaceA::haha << endl;

        return 0;
    }

命名空间是可以嵌套使用的。

namespace my_spaceA {
    int haha = 1;
    namespace my_spaceB {
        int haha = 2;
    }
}


using namespace my_space;
using namespace my_spaceA;
/**
    * @brief  创建test对象
    * @param  
    * @retval 
    */ 
    int main(int argc, char **argv)
    {
        cout << "hello c++ " << my_spaceA::my_spaceB::haha << endl;

        return 0;
    }

1.3 bool变量

c语言是在c99标准中才支持bool变量
在头文件stdbool.h中定义

//
// stdbool.h
//
//      Copyright (c) Microsoft Corporation. All rights reserved.
//
// The C Standard Library <stdbool.h> header.
//
#ifndef _STDBOOL
#define _STDBOOL

#define __bool_true_false_are_defined   1

#ifndef __cplusplus

#define bool    _Bool
#define false   0
#define true    1

#endif /* __cplusplus */

#endif /* _STDBOOL */

/*
 * Copyright (c) 1992-2010 by P.J. Plauger.  ALL RIGHTS RESERVED.
 * Consult your license regarding permissions and restrictions.
V5.30:0009 */

在c++中也支持了这个bool变量,具体操作就不写了。

1.4 三目运算符加强

先看看c语言用法:

int main(int argc, char **argv)
    {
        int a = 10;
        int b = 12;
        int c = 0;

        c = (a > b) ? a : b;
        printf("ghhgah %d\n", c);

        return 0;
    }

三目运行符做右值,判断出一个值然后赋值给c。
如果要做左值的话,直接添加取地址

 *((a > b) ? &a : &b) = 50;

但是c++不一样,c++直接默认直接三目做左值(默认就已经返回引用)

int main(int argc, char **argv)
    {
        cout << "hello c++ " << my_spaceA::my_spaceB::haha << endl;

        int a = 10;
        int b = 12;
        int c = 0;

        (a > b) ? a : b = 50;

        printf("a b %d %d\n", a, b);

        return 0;
    }

可以直接赋值

1.5 const增强

在c语言对const int a = 10;这个变量a虽然是常量,但是编译器并没有严格约束,如果用指针操作a的地址还是可以修改的。

但是在c++中,就对const做了严格的约束,会把const int a=10;存储到一个符号表中,键值是a,值是10,这样通过a就能找到10。

如果int *p = &a; 这时候,c++会临时申请一个变量,并且把地址返回给p,这样操作之后,常量a是没有被改变的。

1.6 枚举的增强

其实说增强到也不像,c语言中用到枚举的时候,其实申请枚举变量是可以用数字来代替的,但是好的习惯,都用枚举了,还用什么数字,用枚举了自然就用别名。

c++中的做法就是,用枚举申请的变量是不能用数字赋值的,直接把这个封死了,只能用别名赋值。

1.7 引用

引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。

C++ 引用 vs 指针
引用很容易与指针混淆,它们之间有三个主要的不同:

  1. 不存在空引用。引用必须连接到一块合法的内存。
  2. 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  3. 引用必须在创建时被初始化。指针可以在任何时间被初始化。
    来自菜鸟教程:https://www.runoob.com/cplusplus/cpp-references.html

引用的特点:
引用不分配内存,一个变量可以多次引用,&前面有数据类型时,是引用,其他皆为地址。

引用的实际例子:

int main(int argc, char **argv)
    {
        cout << "hello c++ " << my_spaceA::my_spaceB::haha << endl;

        int a = 10;
        int b = 12;
        int c = 0;

        //(a > b) ? a : b = 50;
        //rea就是a的引用,之后往rea写值就相当与给a修改值
        int & rea = a;
        rea = 33;

        printf("a b %d %d\n", a, b);

        return 0;
    }

引用作为函数参数:

int main(int argc, char **argv)
 {
     cout << "hello c++ " << my_spaceA::my_spaceB::haha << endl;

     int a = 10;
     int b = 12;
     int c = 0;

     //(a > b) ? a : b = 50;
     int & rea = a;
     rea = 33;
     swap(a,b);
     printf("a b %d %d\n", a, b);

     return 0;
 }
    
int swap(int& a, int& b)
{
    int temp = 0;
    temp = a;
    a = b;
    b = temp;
    return 0;
}

这样就可以交换a和b的值了。

总结:感觉引用和指针的用法差不多,差的就是引用限制的比较多,指针比较灵活,就是因为指针比较灵活,才容易错,引用限制多了,不用出错,不会出现野指针之类的。

1.8 引用的本质

引用的本质是常指针int *const p;
指针p不能修改,但是指向的内容可以被修改

void swap(int *const p)
{	
	*p = 300;
}	

这个指针p指向的内容是可以被修改的。

但是我们写引用代码的时候,就不能这么理解,就直接当做引用,因为一些细节被编译器隐藏了,我们看不到,*号就被隐藏了,如果还当做指针,就会理解错误。

1.9 常量指针

c++中常量指针也是存储在常量区,跟上面的常量的存储方式一样,另外数组名在存储在常量区,然后有一个指针指向内存的地址。

1.10 引用作为函数返回值

首先,引用作为函数返回值的时候,不能返回局部变量的引用,因为作用域的问题,可以返回静态全局变量和堆的遍历的引用。
如果用给一个普通变量接收这个函数返回值,就相当于把函数的返回值拷贝到接收的变量中。
如果用一个引用变量来接收的话,接收到的函数返回值就是一个引用。
最重要一点是引用作为函数返回值是可以作为左值的(我现在也不理解函数返回值作为左值是什么鬼)

int& getA()
{
	static int a = 10;
	return a;
}

getA() = 1000;   //不知道这个具体用处

1.11 指针引用

c++引入了引用之后,指针也可以使用引用,使用引用了之后,比用二重指针方便多了。

int mem_a(struct student* &re)
{
    //传入的参数是引用,引用的意思就是传入自己   
    //struct student *re 等于外面申请的指针变量,操作这个就会影响到外面指针变量的值
    re = (struct student *)malloc(sizeof(struct student));
    printf("------- re %p\n", re);
    if(re == NULL) {
        return -1;
    }
    re->id = 10;
    strcpy(re->name, "lili");
    return 0;
}

int free_a(struct student* &re)
{
    if(re == NULL) {
        return 0;
    }
    free(re);
    re = NULL;
    return 0;
}

/**
    * @brief  创建test对象
    * @param  
    * @retval 
    */ 
    int main(int argc, char **argv)
    {
        cout << "hello c++ " << my_spaceA::my_spaceB::haha << endl;

        struct student * s = NULL;
        mem_a(s);
        printf("------- s %d %s\n", s->id, s->name);
        free_a(s);
        return 0;
    }

写了这个代码之后,对引用有了更深刻的认识,引用就好像把外部的变量引用进函数内部,操作函数内部这个变量就相当于操作外部的变量。(可以理解是编译器把*号屏蔽掉了)。

1.13 const引用

const引用可以作为常量的引用。
const int &a = 10;
不过const的只要作用还是作为函数形成的时候,保存参数不被修改的。