C++核心编程第一部分

可移植性要考虑硬件(不同的芯片)和软件(不同的操作系统)
OOP:面向对象设计

c++支持的编程流派

1 C语言的面向过程
2 OOP面向对象设计
3 模板和泛型编程

编写c++需要的几个套路

include 标准输入输出流,相当于c语言的stdio
using namespace std;//使用标准命名空间,命名空间可以简单理解成一个房间

c++输出流的几个问题

1 如果想要换行需要在后面追加

命名空间的几个问题

命名空间里面可以存放的东西

变量 函数 结构体 类。。。

命名空间是为了解决不同代码下函数名或其他成员重名的问题,这样大大提高了可移性

命名空间 必须声明在全局作用域下,不可以命名到局部作用域下

命名空间可以嵌套命名空间

namespace B
{
    int num=10;
    namespace A
    {
        int num=20;
    }
}

可以直接用B::num访问B空间下的num,用B::A::num访问A空间下的num

命名空间是开放的,可以随时给命名空间添加新的信息

namespace B
{
    int a=10;
}
namespace B
{
    int b=20;
}
//此时命名空间是同时含有a和b的,可以随时往里面添加新成员

命名空间可以是匿名的

namespace 
{
    int c=10;
    int d=30;
}
//本例中没有给命名空间命名,就是命名,相当于在全局中声明,相当于
//static int c=10;static int d=30;

命名空间可以起别名

namespace veryLong
{
    int e=40;
}
void test()
{
    namespace else = veryLong;//这样就给veryLong命名空间起了别名,用els来代
    cout <<veryLong::e<<endl;
    cout <<else::e<<endl;
    //上述两行代码效果医院
}

using声明以及using编译指令

就近原则和using声明同时出现就会出错,尽量避免,但是using编译指令与就近原则
同时出现优先使用就近,当没有就近原则的时候,同时使用多个using编译指令需要加作用域区分

C++对C语言的增强和拓展

1 全局变量检测增强

int a;
int a=10;
上述代码在C语言中可以编译通过,但是C++不行

2 函数检测增强

get(w,h)
{
   return w*h;
}
void test()
{
   printf("%d\n",get(10,10,10));
}

上述代码在C语言中是可以编译通过,但是C++不行。说明C语言的返回值没有检测,函数调用参数个数没有检测

3 类型转换检测增强

void test()
{
    char *p=malloc(64);
    //malloc的返回值是void*,但是上述代码左边是char *
}

上述代码在C语言里是可以编译通过的,但是在C++里是不行的必须得写成下面这样才行

void test()
{
    char *p=(char *)malloc(64);//加入强制转换类型
}

4 struct增强

struct Persion
{
    int age;
    void func();//C语言下结构体中不能有函数
}
void test()
{
    struct Persion p;//C语言中创建结构体变量必须加struct关键字
    p.age=100;
}

C++中的结构体可以放函数,而且可以不加struct关键字

5 bool类型的扩展

C语言下没有这个数据类型,该数据类型代表真(1)和假(0)
将非零的数都转换为 1
bool类型只占一个字节的空间

6 三目运算符增强

void test()
{
    int a=10;
    int b=20;
    printf("%d"a>b?a:b);
    a>b?a:b;//在C语言中是不允许这行代码的存在的但是C++可以,而且最后b=100
            //这是因为在C语言中三目运算符返回的是一个值,而c++返回的是一个变量

}

const增强

全局const

```c
const int a=100;
void test()
{
    //a=10;//这样直接改值会报错,直接修改不行
    //下面通过间接修改的方式修改,这种方式在C语言里是可以通过编译的
    //虽然没有语法错误,但是执行生成的可执行文件会报错,
    //因为定义全局变量之后,受到常量区的保护,运行修改失败
    int *p=&a;
    *p=20;
}
```

局部const

void test()
{
    const int b=100;
    //b=200;//直接这么修改依旧会报错,但是用下面的间接修改的
    //方式是可以修改成功的
    int *p=&b;
    *p= 20 ;//因为此时的全局变量分配到栈区上,相当于在内存上的
}

int arr[a];在C语言下,const是伪常量,是不能用来初始化数组的
在C++下,全局const的结论和C语言的结论一样,但是C++下局部const的间接修改
的方式虽然编译通过了,而且能运行可执行文件,但是运行的结果不会修改值,是修改
失败的,而且int arr[a];是可以这么对数组初始化的,所以C++下面const修饰的是一个真正的常量

原理大概描述

C++能做到上述操作的原因是把const修饰的放到了符号表里 ,符号表里是用键值对的
形式,一个常量对应一个值,只要你引用常量就会去访问符号表的键值对。
int *p=(int *)&b;在C++里能执行但没效果的原因是,这条代码对C++相当于
int temp =b;
int *p=&temp;最终他指向的是temp这个自动生成的中间变量。
当对const修饰的局部变量取地址的时候,编译器给变量分配临时内存空间temp(在栈区上)
,p指针指向的是temp

在C语言中const修饰的变量是一个外部链接属性的,在c++中默认是内部链接属性
(该变量可以在本文件使用,但是在外部文件就不能用了),除非加入extern关键字
使他变为外部链接属性

const分配内存的情况

1 对于const变量取地址会分配临时内存 
2 使用普通变量来初始化const变量,比如下面这种
    ```c++
    void test()
    {
        int a=10;
        const int b=a;

        int *p=(int *)&b;
        *p=1000;//这种情况下在c++里是可以修改成功的(此时分配到内存里)
        //把a换成10,那么这样是不能修改成功的
    }
    ```
3 对于自定义数据类型,也会分配到内存里
```c++
struct persion
{
    string name;//c++里一个字符串类,如果想用这个需要包含头文件include<string>
    int age;
}
void test()
{
    const persion p;
    //p.age=10;//这种直接修改依旧会报错
    persion *pp=(persion *)&p;//这种间接修改的方式就可以实现修改
    (*pp).name="tom";
    pp->age=10;
}
```

用常量初始化就绝不会被修改
在C++里尽量用const替换#define

引用

int &b=a;
表示对a的引用,引用的本质是起别名
引用的基本语法 类型 &别名=原名
引用必须初始化,光写int &b;会报错
引用一旦初始化后,就不可以指向其他变量

对数组建立引用

1 直接建立引用
int arr[10];
int (&p)[10]=arr;//这样编写即可直接引用

2 先定义出数组类型,再通过类型定义引用
typedef int(p)[10];//表示用p 代表一个长度为10的整型数组
p &p2=arr;

可以为一个变量建立多个引用,起多个别名
用引用的方式把变量传入函数,可以更改变量的值

引用的注意事项

1 引用必须引一块合法的内存空间
    int &a=10;//这么写是不行的
2 不要返回局部变量的引用
函数的返回类型可以是引用
int& func()
{
    int a=0;
    return a;
}
void test()
{
    int &ref=func();
    count << "ref"<<ref<<endl;
    count <<"ref<<ref<<endl;"
}//上述代码的现象是第一次引用是10,第二次释放局部变量的内存之后就是随机值了
当函数返回值是引用,那么函数的调用可以作为左值,比如
fun2()=1000;
3 常量的引用
void test()
{
    //int &ref=10;//上文提到这么写是会直接报错,但是下面这样写不会报错
    const int &ref=10;//加了const之后,相当于写成int temp=10;const int &ref = temp;
    //并且可以通过如下方式来对10进行修改
    int *p=(int *)&ref;//(int *)是进行一个强制类型转换
    *p=10000;
    //这样ref就被改成了10000
}
常量引用的使用场景 const修饰函数形参防止误操作

引用的本质在C++内部实现是一个指针常量,引用所占的空间大小与指针相同
利用引用可以简化指针,可以直接用同级指针的 引用,给同级指针分配空间

函数重载的实现原理

由编译器自己给你改成别的名字,不同的编译器改的名字不同,这地方咱们普通用户
就不用操心了

C++调用C语言函数

C++中的函数重载会对函数名做修饰,所以调用C语言函数会发生链接错误需要下面的方式处理

extern c

如果C++和C语言混合编程,在c++里想调用C语言代码下的一个函数,你需要加入
extern "C" void test() 这样来告诉编译器用C语言的方式去链接这个函数,同时这样写,就不需要
include "test.h"(声明test的头文件了)

另一种方式

但是上述书写方式如果需要调用的函数太多就很麻烦,一般不那样写
我们一般在C语言的头文件test.h开头加入
#ifdef __cplusplus
extern "C" {
#endif
在test.h文件末尾加入
#ifdef __cplusplus
}
#endif
然后在C++源码中包含include "test.h"就可以了

类和对象的基本概念

面向对象的三大特性,封装 继承 多态,C语言下虽然也有封装但是缺点是属性 和 方法是分离的
导致别的东西也可以调用你的方法,造成混乱

C++封装

理念:将属性和行为(成员方法)作为一个整体来表现生活中的事物
    将属性和行为加以权限控制,权限分为3种
public 公共权限
成员在类内 类外都可以访问
private 私有权限
成员在类内可以访问 类外不行
protected 保护权限
成员在类内可以访问 类外不行
该权限和继承有关,子类可以继承来访问父类的东西

class和struct的区别是class的权限是默认是私有的,struct默认是公共的
尽量将成员属性设置为私有,这样自己可以控制读写权限,可以对设置的内容加一个有效性验证
char *可以隐式类型转换为string

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值