C++与C的区别一

1. C++风格数组初始化:

#include <iostream>
#include <array>

using namespace std;

void main()
{
    //CPP一维数组初始化
    array<int, 10>MyInt{ 1,2,3,4,5,6,7,8,9,10 };
    for (auto i : MyInt)
    {
        cout << i << " " << (void *)&i << endl;
    }

    //CPP二维数组初始化
    array<int, 10>MyInt1{ 11,2,3,4,5,6,7,8,9,10 };
    array<int, 10>MyInt2{ 21,2,3,4,5,6,7,8,9,10 };
    array<int, 10>MyInt3{ 31,2,3,4,5,6,7,8,9,10 };

    array<array<int, 10>, 3>myInt{ MyInt1,MyInt2,MyInt3 };

    for (auto j : myInt)
    {
        for (auto i : j)
        {
            cout << i << " ";
        }
        cout << endl;
    }

    cin.get();
}

 2. CPP别名:

#include <iostream>

using namespace std;

//一般情况,原则上都用using取代typedef
//typedef处理不了模板,处理不了命名空间,统一用using
typedef double DB;        //C风格
using DBCPP = double;    //CPP风格别名

//数组别名
typedef int a[10];
using IntArray = int[10];

//函数指针
typedef int(*p)(int a, int b);        //函数指针类型,p
using pFun = int(*)(int a, int b);    //CPP函数指针别名

//函数指针数组
typedef int(*pa[10])(int a, int b);
using ppFun = int(*[10])(int a, int b);

void main()
{
    cout << sizeof(DB) << endl;       //8
    cout << sizeof(DBCPP) << endl;    //8

    IntArray int1;
    cout << sizeof(int1) << endl;     //40

    cin.get();
}

3. auto 使用:

#include <iostream>

using namespace std;

//C++14自动推理返回值类型
//C++11需要指定返回值类型
auto add(int a, int b)->int        //此处int可换为decltype(a+b)
{
    return a + b;
}

//数控科技面试题:请问f是什么?
auto (*f)()->int(*)();    
//int(*      (*fx)()       )()    //返回值是函数指针

//请推理下面pf是什么类型?
auto pf1()->auto(*)()->int(*)()
{
    return nullptr;    //返回空指针
}

auto pf2(void)->auto(*)(int x)->int(*)(int a,int b)
{
    return nullptr;    //返回空指针
}
//int(*       (*)(int x)       )(int a,int b)
//int(*       (*   pf2(void)        )(int x)       )(int a,int b)
//int(*(*   (void) )(int))(int,int)

auto go(int a, int b)->auto(*)()->int (*)(int, int(*)(int, int));
//int (*     (*)()      )(int, int(*)(int, int))
//int (*     (*   go(int a, int b)           )()      )(int, int(*)(int, int))
//int (* (* (int, int))(void))(int, int (*)(int,int))

void main()
{
    cout << typeid(f).name() << endl;
    cout << typeid(pf1).name() << endl;
    cout << typeid(pf2).name() << endl;
    cout << typeid(go).name() << endl;

    cin.get();
}

4. 函数模板的别名:

#include <iostream>
#include <array>

using namespace std;

//C++14自动推理返回值类型
//C++11需要指定返回值类型
template<class T1,class T2>
auto add(T1 t1, T2 t2)->decltype(t1 + t2)        //此处int可换为decltype(a+b)
{
    return t1 + t2;
}

//函数模板的别名
template<class T> using t = T;
template<class T> using tp = T*;
template<class T>
void show(T tx)
{
    t<int> t1(tx);        //一旦使用别名必须指定类型 <int>
    tp<int> tp1(&tx);    //初始化指针
    cout << t1 << " " << tp1 << endl;
}

template<class T> using ten = array<T, 10>;

void main()
{
    cout << add(1, 2) << endl;            //3
    cout << add(1.1, 2.2) << endl;        //3.3

    int a = 10;
    show(a);    

    using IntArray = array<int, 10>;    //相当于为模板起了别名,明确地指明了类型为array<int, 10>
    array<int, 10> MyInt;                //此时array<int, 10>代表一个类型
    IntArray MyInt2;

    //template<class T> using t = array<T, 10>;    //error C2951: 模板 声明只能在全局、命名空间或类范围内使用
    ten<int> t1{ 1,2,3,4,5,6,7,8,9,10 };//模板别名不明确类型
    for (auto i : t1)
    {
        cout << i << " ";
    }

    cin.get();
}

5. 收缩转换:

#include <iostream>

using namespace std;

void main()
{
    char ch1(787878);
    char ch2{ 787878 };    //赋初始值最好用大括号,保证数据类型安全转换

    cout << (int)ch1 << endl;    //-90    编译通过,产生溢出
    cout << (int)ch2 << endl;    //编译不通过,error C2397: 从“int”转换到“char”需要收缩转换

    cin.get();
}

6. 二进制:

#include <iostream>

using namespace std;

void main()
{
    int a = 0b1001;
    int b = 0B1101;

    cout << a << endl;    //9
    cout << b << endl;    //13

    cin.get();
}

7. 常量表达式constexpr :

#include <iostream>

using namespace std;

int get1()
{
    return 5;
}

constexpr int get2()    //constexpr返回值或其他表达式为常量
{
    return 5;
}

void main()
{
    //int a[5+get1()];    //error C2131: 表达式的计算结果不是常数
    int a[5 + get2()];    //编译成功

    cin.get();
}

 8. lambda 表达式:

#include <iostream>
using namespace std;

void main()
{
    [] {cout << "hello world!" << endl; }();        //解决函数怀孕现象

    auto fun = [] {cout << "hello" << endl; };        //函数指针
    fun();//调用

    [] {cout << "hello C" << endl; }();                //匿名lambda表达式

    [](char *str) {cout << str << endl; }("你好!");//带参数(匿名)

    auto fun1 = [](double a, double b) {return a + b; };
    cout << fun1(10, 20.1) << endl;        //30.1

    auto fun2 = [](double a, double b)->int {return a + b; };    //指定返回值类型,->在()与{}之间
    cout << fun2(10, 20.1) << endl;        //30

    int num = 100;
    auto func = [](int num) {num = 5, cout << num << endl; };//遵循副本机制
    func(num);                        //5
    cout << "main=" << num << endl;    //main=100

    cin.get();
}
#include <iostream>
#include <array>
#include <algorithm>
using namespace std;

void main()
{
    int num1 = 100;
    int num2 = 99;
    //[]() {cout << num1 << " " << num2 << endl; }();//error C3493: 无法隐式捕获“num1”,因为尚未指定默认捕获模式
    [=]() {cout << num1 << " " << num2 << endl; }();    //100 99

    //[=]() {num1=10,num2=20,cout << num1 << " " << num2 << endl; }();//error C3491: “num1”: 无法在非可变 lambda 中修改通过复制捕获
    [&]() {num1 = 10, num2 = 20, cout << num1 << " " << num2 << endl; }();//=只能读不可写;&读写外部变量
    cout << "main=" << num1 << " " << num2 << endl;        //main=10 20

    int num3 = 100;
    int num4 = 99;
    [=]()mutable {num3 = 10, num4 = 20, cout << num3 << " " << num4 << endl; }();    //10 20   mutable起到副本作用
    cout << "main=" << num3 << " " << num4 << endl;                                    //100 99

    int a = 10, b = 9, c = 8;
    //a可读可写,bc只可读
    [&a, b, c]() {a = 20, cout << a << " " << b << " " << c << endl; }();    //20 9 8
    
    //mutable副本,能读能写,读的原本,写的副本
    [a, b, c]()mutable {a = 1, b = 2, c = 3, cout << a << " " << b << " " << c << endl; }();    //1 2 3 

    array<int, 10>MyInt{ 1,2,3,4,5,6,7,8,9,10 };
    //lambda表达式嵌入使用
    for_each(MyInt.begin(), MyInt.end(), [](int num) {cout << num << " "; });                //显示
    cout << endl;
    for_each(MyInt.begin(), MyInt.end(), [](int &num) {num += 1, cout << num << " "; });    //修改
    cout << endl;
    for_each(MyInt.begin(), MyInt.end(), [](int num) {cout << num << " "; });                //显示

    cin.get();
}

9. 函数包装器:

#include <iostream>
#include <functional>    //函数包装器头文件

using namespace std;
using std::function;    //函数包装器

void go()
{
    cout << "go" << endl;
}

int ADD(int a, int b)
{
    return a + b;
}

void main()
{
    function<void(void)> fun1 = go;                                    //包装函数
    fun1();

    function<void(void)> fun2 = []() {cout << "go lambda" << endl; };//包装lambda表达式
    fun2();

    function<int(int, int)> fun3 = ADD;
    cout << fun3(10, 19) << endl;

    function<int(int, int)> fun4 = [](int a, int b)->int {return a + b; };
    cout << fun4(10, 19) << endl;

    cin.get();
}

10. 模板元

#include <iostream>
using namespace std;

int get50(int n)
{
    if (n == 1)
        return 1;
    else if (n == 2)
        return 2;
    else
        return get50(n - 1) + get50(n - 2);
}

//递归调用:函数反复调用,等待返回,浪费时间较多
//模板元实现递归加速
//执行速度快,编译的时候慢,代码会增加
//把运行的时间节约在编译的时候
//常使用在递归加速,游戏优化,此处的模板元仅仅适用于C++11
template<int N>
struct data
{
    //递归表达式
    enum 
    { 
        res = data<N - 1>::res + data<N - 2>::res
    };
};

template<>
struct data<1>
{
    enum
    {
        res = 1
    };
};

template<>
struct data<2>
{
    enum
    {
        res = 2
    };
};

void main()
{
    cout << data<40>::res << endl;    //模板元,代码加速(将运行时间放在编译中执行)
    cout << get50(40) << endl;
    
    cin.get();
}

11. C++中的const :

#include <iostream>
using namespace std;

void run1(const int *p);        //可改变地址,不可改内容
void run2(int const *p);        //
void run3(int * const p);        //不可改地址,可改内容
void run4(const int * const p);    //地址内容均不能改
void run5(int const * const p);    //

void main()
{
    //C语言中:
    //const int num = 10;
    //*(int *)(&num) = 4;
    //printf("%d
", num);    //4

    //const int n = 10;
    //int a[n];                //C++编译器自动优化,将n直接替换为10

    //int a = 10;
    //const int n = a;        //此时C++编译器不敢乱优化,不敢把n直接替换为a
    //int data[n];            //error C2057: 应输入常量表达式

    //const int a = 10;
    //const int n = a;
    //int data[n];

    //const int num = 10;
    //*(int *)(&num) = 3;
    //cout << (void *)&num << endl;    //优化,强行替换为10,寄存器
    //cout << *(&num) << endl;    //10
    //cout << num << endl;        //10

    //int a = 10;
    //const int num = a;
    //*(int *)(&num) = 3;
    //cout << (void *)&num << endl;    //直接读内存,此时为变量,不敢优化
    //cout << *(&num) << endl;    //3   
    //cout << num << endl;        //3

    const int num[5] = { 1,2,3,4,5 };
    const int *p = num;
    *(int *)p = 100;        //const数组没有优化,可以间接改变
    for (auto i : num)
        cout << i << " ";    //100 2 3 4 5
    cout << endl;

    cin.get();
}

12. 智能指针:

#include <iostream>
#include <memory>
#include <Windows.h>    
using namespace std;

void cmem()
{
    while (1)
    {
        double *p = new double[1024 * 1024 * 10];
        Sleep(3000);
        delete p;        //释放
        Sleep(3000);
    }
}

void autoptr()
{
    while (1)
    {
        double *p(new double[1024 * 1024 * 10]);
        auto_ptr<double>autop(p);    //创建智能指针,接管这片内存,会自动回收

        Sleep(3000);
    }
}

void autoptrnew()
{
    while (1)
    {
        Sleep(6000);
        unique_ptr<double>p(new double[1024 * 1024 * 10]);
        Sleep(6000);
    }
}

void main()
{
    //cmem();
    autoptr();
    autoptrnew();

    cin.get();
}

13. 多元数组 tuple :

#include <iostream>
#include <tuple>
using namespace std;

//多元数组,存取不同的数据类型
void main()
{
    char ch = 'X';
    short sh = 12;
    int num = 1234567;
    double db = 123;
    char *p = "calc";

    tuple<char, short, int, double, char *>MyTuple(ch, sh, num, db, p);

    auto autov1 = get<0>(MyTuple);    //多元数组不能用for(auto i:MyTuple)的方式遍历
    cout << autov1 << endl;
    auto autov2 = get<1>(MyTuple);
    cout << autov2 << endl;
    auto autov3 = get<2>(MyTuple);
    cout << autov3 << endl;
    auto autov4 = get<3>(MyTuple);
    cout << autov4 << endl;
    auto autov5 = get<4>(MyTuple);
    cout << autov5 << endl;

    cin.get();
}

14. 左值引用与右值引用:

#include <iostream>
using namespace std;

//C++能用引用的情况,就别用指针
void change(int & rnum)
{
    rnum = 111;
}

void main0501()
{
    //int num(10);        //num是左值,有内存实体,可以赋值    int num=10;
    //int & rnum(num);    //引用&就是变量的别名
    //
    //rnum = 1;            //rnum等价于num的别名
    //change(num);

    //cout << num << endl;    //111

    //int num = 1;
    //int data = 0;
    //cout << (void *)&data << endl;
    //data = num + 1;
    //data = num + 2;
    //data = num + 3;
    //cout << data << endl;

    //右值引用
    int num = 1;
    int && rnum(num + 4);    //右值引用,快速备份寄存器的值。编译器会自动回收
    printf("%p
", &rnum);

    //若是左值引用,需要两步:
    int data = num + 4;
    int &rdata(data);

    int a[5]{ 1,2,3,4,5 };
    int *p(a);
    cout << *p << endl;        //1

    int * & rp(p);            //左值引用改变指针  & 放在类型与变量名之间
    rp += 1;
    cout << *p << endl;        //2

    int * && rrp(p + 2);    //右值引用改变指针 && 
    //int * && rrp(&a[1]);
    cout << *rrp << endl;    //4

    cin.get();
}

void showit(int && rrnum)    //右值引用
{
    cout << rrnum << endl;
}

void main()
{
    int a[5]{ 1,2,3,4,5 };

    showit(a[3] + 2);

    //移动语义:将左值转化为右值(左值一定可以变为右值,右值不一定可变为左值)
    showit(move(a[3]));

    cin.get();
}

15. 引用的本质:

#include <iostream>
using namespace std;

void main0601()
{
    int num = 10;
    int data = 20;
    int & rnum(num);    //引用一旦初始化,就不会再引用其他变量
    rnum = data;

    cout << num << endl;    //20
    cout << data << endl;    //20

    cin.get();
}

void main()
{
    double db;
    //double & rdb;                    //error C2530: “rdb”: 必须初始化引用
    double & rdb(db);
    cout << sizeof(rdb) << endl;        //8

    struct MyStruct        //引用的本质是指针实现的,为了简化程序
    {
        double & rdb;
    };
    cout << sizeof(MyStruct) << endl;    //4

    cin.get();
}

 16. 引用指针以及作为函数参数和函数返回值:

#include <iostream>
using namespace std;

//改变指针,需要二级指针
//C++中可用引用
void main0701()
{
    int a(4);            //初始化为4
    int *p(new int(5));    //开辟int大小空间,值为5
    cout << a << endl;    //4
    cout << *p << endl;    //5

    //int & ra(a);        //引用变量
    //int * & rp(p);    //引用指针
    //ra = 3;
    //*rp = 12;
    //cout << a << endl;    //3
    //cout << *p << endl;    //12

    int && rra(move(a));    //右值引用,有内存实体就直接引用,没有内存实体则新开辟内存
    int * && rrp(move(p));
    rra = 1;
    cout << rra << endl;
    cout << a << endl;

    //int        整数类型
    //int &        引用整数,本质是指针
    //int &&    引用整数,本质是指针,能处理左值(move)   和右值

    cin.get();
}

int num1 = 10;
int num2 = 20;

void change(int * &rp)    //C++中能用引用就别用指针
{
    rp = &num2;
}

void main0702()
{
    int *p = &num1;
    change(p);
    cout << *p << endl;    //20

    cin.get();
}

void main0703()
{
    int *p(nullptr);

    int **pp(&p);
    int ** &rpp(pp);        //VS2015    C++14

    //int **pp(&p);
    //int(** (&rpp))(pp);    //VS2013    C++11

    cin.get();
}

void main0704()
{
    int ***ppp(nullptr);
    int *** & rppp(ppp);

    cin.get();
}

int data1 = 10;
int data2 = 20;
int *p = &data1;

void changeit(int ** &rpp)
{
    *rpp = &data2;
}

void main0705()
{
    int **pp = &p;    //二级指针
    cout << **pp << endl;    //10
    changeit(pp);
    cout << **pp << endl;    //20

    cin.get();
}

//返回一个引用a
int getdata()
{
    int num = 10;
    return num;        //函数返回值有副本机制
}

void main0706()
{
    cout << getdata() << endl;    //10

    cin.get();
}

//函数返回值有副本机制,返回变量
//栈区,自动回收、释放,返回为指针不能指向栈区,返回为引用不能应用栈区
int & getdata1()
{
    int num = 10;
    return num;        //函数返回值有副本机制
}

void main0707()
{
    int & rnum = getdata1();    //此时引用的是原来的内存,调用后已经释放
    cout << "hello" << endl;
    cout << rnum << endl;        //此处结果并不是10

    int rnum2 = getdata1();        //拷贝到新的内存rnum2中
    cout << rnum2 << endl;        //10

    cin.get();
}

int & getdata2()
{
    int *p(new int(5));    //堆区 
    return *p;
}

void main0708()
{
    int & rnum = getdata2();    //此时引用的是堆区
    cout << "hello" << endl;
    cout << rnum << endl;        //5

    cin.get();
}

char * & getcode()
{
    char *p = "hellohellohello";    //常量字符串-->代码区(与程序供存亡)
    return p;                        //p在栈上,但指向内容在代码区
}

void main()
{
    char * &rp = getcode();            //指针,引用p,但这个p在栈上,消亡了
    char * newp = rp;    //保存rp存储代码区地址
    cout << "hello china" << endl;
    cout << newp << endl;    //hellohellohello
    cout << rp << endl;        //乱码

    cin.get();
}

17. 引用数组:

#include <iostream>
using namespace std;

void main0801()
{
    int a[5]{ 1,2,3,4,5 };                            //一维数组
    int *pa[5]{ a,a + 1,a + 2,a + 3,a + 4 };        //指针数组

    int b[2][3]{ 1,2,3,4,5,6 };        //二维数组
    //二维数组,每一个元素是一个指针
    int *pb[2][3]{ &b[0][0],&b[0][0] + 1,&b[0][0] + 2,&b[0][0] + 3,&b[0][0] + 4,&b[0][0] + 5 };

    int *p1(new int[5]{ 1,2,3,4,5 });                //堆上的一维数组
    int(*p2)[4] = new int[3][4]{ {1,2,3,4},{5,6,7,8},{9,10,11,12} };    //堆上的二维数组

    cin.get();
}

void main0802()
{
    int a[5]{ 1,2,3,4,5 };
    int(&ra)[5](a);            //引用一维数组
    for (auto i : ra)
        cout << i << " ";
    cout << endl;

    int *pa[5]{ a,a + 1,a + 2,a + 3,a + 4 };
    int *(&rpa)[5](pa);        //引用指针数组
    for (auto i : rpa)
        cout << *i << " ";
    cout << endl;

    cin.get();
}

void main0803()
{
    int *p1(new int[5]{ 1,2,3,4,5 });
    int **pp(new int *[5]{ p1,p1 + 1,p1 + 2,p1 + 3,p1 + 4 });    //堆上指针数组
    int * &rp(p1);
    int ** &rpp(pp);

    cin.get();
}

void main0804()
{
    int b[2][3]{ 1,2,3,4,5,6 };        //二维数组
    //二维数组,每一个元素是一个指针
    int *pb[2][3]{ &b[0][0],&b[0][0] + 1,&b[0][0] + 2,&b[0][0] + 3,&b[0][0] + 4,&b[0][0] + 5 };

    int(&rb)[2][3](b);        //引用二维数组
    int *(&rpb)[2][3](pb);    //引用二维指针数组

    cin.get();
}

void main()
{
    //int(*p2)[4] =  (new int[3][4]{ { 1,2,3,4 },{ 5,6,7,8 },{ 9,10,11,12 } });    //堆上的二维数组
    
    //指向数组的指针,用{}初始化
    int(*p2)[4]{ new int[3][4]{ { 1,2,3,4 },{ 5,6,7,8 },{ 9,10,11,12 } } };
    int(*&rp)[4](p2);    //引用行指针
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
            cout << rp[i][j]<<"   ";
        cout << endl;
    }

    int * (*pp)[4]{ new int *[3][4] };    //堆上开辟二维指针数组
    int * (*&rpp)[4](pp);                //引用二维指针数组

    cin.get();
}

 18. const 与引用:

#include <iostream>
using namespace std;

void main0901()
{
    int num = 100;
    int const & rnum(num);    //const限定引用权限,只能读不能写
    //const int & rnum(num);    //与上面一样
    //rnum=3;    //不能写
    cout << rnum << endl;

    cin.get();
}

//void main0902()
//{
//    int num = 100;
//    int & const rnum(num);    //const放在&右边没有影响
//    rnum=3;    
//    cout << rnum << endl;
//
//    cin.get();
//}

void main0903()
{
    int a[5]{ 1,2,3,4,5 };
    const int(&ra)[5](a);    //只能读不能写
    for (auto i : ra)
        cout << i << " ";
    cout << endl;

    cin.get();
}

void main0904()
{
    //int *p(new int(5));    //堆上指针初始化
    //int *(&rp)(p);
    //*rp = 3;
    //cout << *p << endl;

    const int *p(new int(5));    //指针,指向常量
    const int (*(&rp))(p);        //引用一个指向常量的指针
    //*rp = 3;
    cout << *p << endl;

    cin.get();
}

void main0905()
{
    int * const p(new int(4));    //地址不能变,值可以变
    int * const (&rp)(p);        //引用一个常量指针
    *p = 1;

    cin.get();
}

void main0906()
{
    const int * const p(new int(4));    //地址不能变,值也不能变
    const int * const (&rp)(p);            //引用一个指向常量的常量指针
    //*p = 1;

    cin.get();
}

void main()
{
    int *p(new int(4));
    //const int *(&rp)(p);    //error C2440: “初始化”: 无法从“int *”转换为“const int *&”
    const int *(&rp)((const int *&)p);    //强制转换

    cin.get();
}

 19. 引用与函数指针:

#include <iostream>
#include <cstdlib>
using namespace std;

//函数指针引用作为参数,可以改变函数指针
//函数指针引用作为返回值,可以实现调用getitp(p)("hello world");
int gocmd(const char *cmd)
{
    system(cmd);
    return 1;
}

int showcmd(const char *cmd)
{
    cout << cmd << endl;
    return 1;
}

void change(int(* & p)(const char *cmd))    //函数指针的引用做参数
{
    p = showcmd;
}

//getp()返回一个函数指针
int(*    getp()    )(const char *cmd)
{
    int(*( p))(const char *cmd)(gocmd);
    return p;
}

//getitp()返回一个函数指针的引用,并且参数是一个函数指针的引用
int(* &   getitp(   int(*& p)(const char *cmd)    )     )(const char *cmd)
{
    p = showcmd;
    return p;
}

void main()
{
    int(*p)(const char *cmd)(gocmd);    //定义函数指针并初始化
    //p("calc");

    ////change(p);
    //p = getp();    //通过返回值来赋值

    //p("echo hello world");

    getitp(p)("hello world");    //首先getitp(p)返回一个函数指针的引用,然后继续执行后面语句

    cin.get();
}

20. 引用与指针的差别:

#include <iostream>
using namespace std;

struct MyStruct
{
    int *p1;        //4
    int & p2;        //4
    double & p3;    //4
};        //引用本质就是指针

//int & getint1()
//{
//    int a = 5;
//    return a;    //返回局部变量或临时变量的地址
//}

int & getint2(int & rint)    //参数、返回都是地址,此时引用的是外部传入的参数
{
    rint = 1;
    return rint;
}

void main()
{
    //cout << sizeof(MyStruct) << endl;

    int a = 10;
    int *p(new int(5));

    //getint2(a);
    //getint2(*p);

    int & ra(a);    //引用,栈上,4个字节

    cin.get();
}

 

原文地址:https://www.cnblogs.com/si-lei/p/9494926.html