[day01]C++与C语言的不同、auto自动变量、函数重载、函数的默认参数、引用、const、new&delete...

1.C++与C语言的不同

C++是强类型语言,C语言是弱类型语言

void main()
{
    //C++注重类型,强类型,严格检查类型
    int *p1=NULL;
    double *p2=NULL;
    p1 = p2; // C++中error C2440: “=”: 无法从“double *”转换为“int *”
            // C语言中warning C4133: “=”: 从“double *”到“int *”的类型不兼容
}

C语言与C++输出宽字符(中文)

C语言:

#include <locale.h>

wchar_t *str = L"中国";
setlocale(LC_ALL, "chs");
wprintf(L"%ls", str);

C++语言:

wchar_t *str = L"中国";
wcout.imbue(std::locale("chs"));
wcout << str;

C++语言初始化变量方法(括号)

int a(5);
double a(3.5);
char *str("china");
wchar_t *str(L"china");

C语言缺陷(引进命名空间的原因)

C语言不允许在相同的工程中的不同文件中定义相同的函数名,全局变量。

C语言一旦定义全局变量,然后定义了和全局变量同名的局部变量,那么将不能引用全局变量了,C++可以用::变量名引用。

命名空间

  1. 命名空间中可以定义变量,函数,类等。
  2. 命名空间可以嵌套。
  3. 没有名字的命名空间可以直接调用。
  4. 命名空间不存在private,public。它是完全公开的。备注:class默认private,struct默认public。
  5. 命名空间如果在块语句内容,作用域是定义开始到块语句结束。
  6. 命名空间可以扩展,namespace 拓展的命名空间 {拓展的内容(变量,函数,类等)};
  7. namespace r = runrunrunrun; //给命名空间起一个别名
  8. 一般来说在命名空间当中定义函数指针,然后再外部让函数指针指向一个函数。

外部变量的不同

C语言使用static在一个文件中定义一个变量,在另一个文件中extern该变量,不会报错,C++报错。

extern.cpp/c

static int a = 10;

main.cpp/c

extern  int a; // C/C++语言不报错当,当有打印a的值的语句的时候编译报错。LNK2001: 无法解析的外部符号 "int a" (?a@@3HA)
extern int a = 5; // C++语言,C语言都不报错,并且都能打印。

注:静态变量的作用于只是该文件内,所以两个a并不是同一个a,可以通过定义一个外部指针变量打印。

全局变量的重定义问题

int g_var;
int g_var = 1;

C语言没问题,C++语言报错,说明C语言不初始化值就相当于只是声明了变量,如果第一条初始化一个值,那么照样报重定义。

C++新增的bool类型

占一个字节,0与1。

三目运算符

(a<b ? a : b) = 30; //C++中是没问题的,C语言报错

可以通过以下方法实现类似C++的功能。

*(a<b ? &a: &b) = 30;

当有常量的时候,C++将也失效。如:(a<b ? 1: b) = 30;

C语言中的三目运算符返回的是变量值,不能作为左值使用

C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方

register区别

C语言中因为register变量可能不存放在内存中,所以不能用“&”来获取register变量的地址。

C++中一旦用”&“取地址,相当于普通变量,存到内存。

2.auto自动变量

auto基础

C++ 98标准/C++03标准

同C语言的意思完全一样:auto被解释为一个自动存储变量的关键字,也就是申明一块临时的变量内存。auto的出现意味着,当前变量的作用域为当前函数或代码段的局部变量,意味着当前变量会在内存栈上进行分配。

平时的double a=10.5;其实就相当于auto double a = 10.5;作用域在整个函数体中。

测试下边的例子,每次都是分配四个字节的内存。

C++ 11标准

在C++11标准的语法中,auto被定义为自动推断变量的类型

auto num = 10.5; //double
auto numA = 10.0/3; //double
auto numB = 10.5f; //float
auto numC = 10.0; //double 只打印出10

C++11中auto double num = 10.5这样定义是会报错的。

auto可以用来遍历一维数组

for (auto data : num) // 泛型C++语法,循环一维数组,常量
{
         std::cout << data<<std::endl;
}

3.函数重载

函数重载成立的条件

  1. 函数参数类型不同
  2. 函数参数个数不同
  3. 函数参数顺序不同
  4. 与返回值无关
  5. 函数重载与函数默认参数冲突,需要你输入的参数类型不一个,个数不一样,顺序不一样不会出现问题,否则一定报错
  6. 反正让编译器觉得歧义的就不行

得到函数地址

因为函数名字都一样所以不能通过函数名得到地址,可以通过函数指针指向具体的函数,得到地址。比如:

void(*pgo1)(int a)=go;
void(*pgo2)(double a)=go;
void(*pgo3)(double a, int b)=go;
void(*pgo4)(int  a, double b)=go;

printf("%p\n",pgo1);
printf("%p\n", pgo2);
printf("%p\n", pgo3);
printf("%p\n", pgo4);

4.函数的默认参数

函数默认参数规则

  1. 默认参数必须放在右边
  2. 默认参数中间不能插入非默认参数
  3. 函数指针没有默认参数,必须全部填入形参
void print(int c,int a = 1, int d=2, int b = 3)
{
    std::cout << a<<b<<c << std::endl;
}
void(*pt1)(int c, int a , int d , int b ) = print;

5.引用

左值与右值

左值:放在赋值号左边可以被赋值的值,必须在内存中有实体。

右值:在赋值号右边取出给左值赋值的值,右值可以在内存也可在寄存器。

左值引用与右值引用

/* 对指针的引用 */
int num1 = 20;
int num2 = 30;
int *p = &num1;
int * &rn1 = p; // p的别名 可以通过*rn1去改变num1的值
cout << p << endl;
rn1 = &num2;
cout << p << endl;

int * &&rn2 = &num1; // &代表引用左值,&&代表引用右值,&num1的值在寄存器中
int *q = rn2; // 用于对象拷贝

函数返回值的引用

// 返回值的引用
int &geta()
{
    int a = 30;
    int &ra = a; 

    return ra;
}

函数返回指针的引用

// 返回对指针的引用
int * & getra()
{
     /*
       注意这个p是个变量,在栈上分配的内存空间用来存放堆上分配内存空间的首地址
     */
     int *p = new int;
     *p = 22;
     int *&rp = p;

     return rp;
}

通过上面两个函数,我们知道如果我们分别通过定义一个变量的引用,一个指针的引用去接收,只能第一次打印成功,一旦那块内存空间被重新使用那么将失效,我们可以理解引用只是一个别名的机制。我们应该顶一个一个变量以及一个指针变量去接收。

int ra = geta();
int *rpa = getra();

而不是

int &ra = geta();
int *&rpa = getra();

 

6.const

C语言中的const

const int a = 10;
int arr[a];

这是不允许的,因为C语言中的const是个假的。

再如可以通过

int *p=&a;
*p=20;

修改a的值。

C++中的const

C++中像上面那样修改a的值是改不掉的,并且int *p=&a;还要强制转换。

对于const_cast<int*>的转换,也不能去掉本身就是const的常量,但是本身是变量的被赋值给一个常量,可以去掉那个常量的属性。

C++中的const会使用一张常量表。

 

7.new/delete

delete说明

delete之后指针变量的值将改变。

给二维数组分配内存空间

int *p = new int[20];
int (*q)[4] = (int(*)[4])p;

new与delete的重载

#include <iostream>
#include <cstdlib>

class Teacher {
public:
    static int cnt;

    Teacher() {
        printf("一个teacher被构造\n");
    }

    ~Teacher() {
        printf("一个teacher被析构\n");
    }

    static void * operator new(size_t size){
        printf("对象被创建.\n");
        Teacher *teacher = ::new Teacher; // 全局的new默认就是去调用构造函数
        cnt += 1;
        return teacher;
    }

    static void operator delete(void *teacher) {
        printf("对象被销毁.\n");
        cnt -= 1;
        ::delete teacher;
    }
};

int Teacher::cnt = 0;

int main(void)
{
    Teacher *t1 = new Teacher;
    Teacher *t2 = new Teacher;
    Teacher *t3 = new Teacher;
    delete t1;

    std::cout << Teacher::cnt << std::endl;

    system("pause");

    return 0;
}

转载于:https://www.cnblogs.com/ifpelset/articles/4492172.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值