C++ & C

第一章

1、::作用域运算符

1.1 全局作用域,直接调用::

2、命名空间

2.1 namespace 用于解决命名冲突问题。

可以存放函数,变量,结构体,类。

namespace zzz {

       void func();

       int a = 10;

2.2 必须定义在全局作用下。

2.3 可以嵌套。

2.4 命名空间是开放的,随时追加内容。

2.5可以匿名命名空间,无名的空间。相当于写了 static 类型,只能在当前文件中使用。

namespace {

       int a = 100;

}

等价于 static int a = 100;

2.6 命名空间可以起别名。

namespace zzz = jjj;

3、using 声明

3.1就近原则

3.2 using使用,避免二义性。

int a = 20;

using namespace zzz:a;

cout << a << endl; // 编译报错,编译器确定不了a。

3.3 using编译指令

using namespace zzz; // 打开命名空间 zzz

4、c++对c语言的增强

4.1 全局变量检测增强

C语言:

int a;

int a = 10; // 编译成功。

C++:

int a;

int a = 10; // 编译失败,a重定义。

4.2 函数检测增强

int test(w,s) {

} // C语言编译成功,c++编译失败(函数入参,返回值检测,函数调用 增强,c++更严格)。

4.3 类型转换检测增强

C语言: char *p = malloc(sizeof(64)); // malloc 返回值是void *

C++:   char *p = (void *)malloc(sizeof(64)); 强转。

4.4 struct 增强,struct 不能实现函数,class 可以加函数

struct Person{

       int age;

};

struct Persion p1; // C语言声明类型必须加struct,c++不用。

4.5 bool类型增强, C语言中没有bool类型,c++中才有(所有非0的值都会默认转换为1)

4.6 三目运算符增强

int a = 10;

int b = 20;

a > b ? a : b = 100; // C语言编译报错:20 != 100 ?  。c++自动转换成 b = 100。(C语言返回的是值,c++返回的是变量)

C语言如果也想用c++一样使用,返回变量地址:

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

4.7 const增强

C语言:

可以通过指针的方式修改 const定义的局部变量(全局变量不可以修改):

const int a = 10; // 伪常量。编译器会分配内存,所有分配内存的值都会以指针的方式被修改。

int *p = (int *) &a;

*p = 20;

默认外部链接,外部可以通过extern 调用。

C++中:

const int b = 20; // 真正常量。以键值的方式定义的b ,指向的值是20 ,不会分配内存,如果前面声明extern 会分配内存,如果是自定义变量也会申请内存。所以不能以指针的方式修改。

int *p = (int *) &a;

*p = 20;  等价于:int tmp = b; int *p = (int *) &tmp; // 编译器临时开辟一段空间tmp(看不到)。

默认内部链接,外部不能使用。

5、尽量用const 替换 #define

#define MAX 3;

在预处理就被替换了,编译器发现不了,没有数据类型,没有作用域,整个文件都存在,但是可以通过 #undef 的方式卸载。

6、引用(给变量取别名)

int a = 10;

int &b = a;  等价于  int * const b = &a; (指针常量) // &在左侧叫引用,在右侧叫取地址。

注意:1、必须初始化。一个变量可以有多个别名,但是一个别名只能指向一个变量。

         2、类型必须要和变量一样。

第二章

1、内联函数:空间换时间c++中代替C语言中宏函数。宏函数有缺陷(提升程序效率)。

#define Math(x,y) x+y   //宏函数定义

1.1 预处理的时候直接替换,存在潜在问题。

1.2 内联函数本身也是一个真正的函数,唯一的区别就是不需要函数调用的开销。

inline int func(int a)  // 内联函数声明

inline int func(int a) {return a++;}  // 内联函数定义

1.3 类内部的成员函数,默认是内联函数。

内联函数的一些限制:

  1. 不能出现循环语句;
  2. 不能出现过多的判断;
  3. 函数体不能太庞大;
  4. 不能对函数进行取地址操作。

出现这四种情况,编译器当普通函数处理。

2、函数的默认参数及其占位参数(C语言中没有)

// 参数后面 = 。。。

// 注意事项:

  1. 当有一个位置参数是默认参数,则后面的参数都必须带有默认参数。
  2. 函数声明和实现,只能有一处实现默认参数。

void fun (int a = 1) {}

// 占位参数,没有什么大用处。函数调用的时候必须要提供这个参数。

void fun1(int a, int){}

3、函数重载

c++中最重要的概念。C语言中函数只能有一个命名,c++中可以(编译器内部把函数进行了改名)。

语法:

  1. 函数命名相同,入参个数,类型或者个数不一样。
  2. 必须在同一个作用域。
  3. 函数返回类型不能作为重载(二义性)。
  4. 当函数重载遇到函数默认参数,注意二义性。
  5. 引用的重载,const也可以作为重载。

4、extern “C” 浅析

一个无法解析的外部命令:链接的时候报错。

在c++中,函数可以发送重载,所以c++编译器可能会把函数偷偷改名。

但是C语言中没有函数重载,所以c++中调用C语言的函数,就会链接错误。 所以extern “C” 就是告诉编译器,该函数按照C语言的方式链接。

通常是在C语言头文件中进行处理:

#ifdef __cplusplus

extern "C"

#endif

#ifdef __cplusplus

}

#endif

5、c++封装

C语言中结构体,属性的行为是分开的,没有严格执行类型转换。c++严格执行类型转换,属性和行为 可以绑定到一起,作为一个整体。

c++类中控制权限:

  1. public  公有成员,在类 内部和外部都可以访问。
  2. protected   保护成员,类内部可以访问,在当前类的子类 也可以访问,类外部不可以访问。
  3. private    私有成员(属性,函数),只能在类的内部可以访问,类外部不可以。

在c++中,struct 和 class 表示一个意思。唯一区别是 stuct 类中默认权限是 public,class默认是private。

建议把成员属性设置为私有,对外提供公有的方法。

6、对象的构造和析构

构造函数和析构函数,编译器自动调用(只会调用一次),完成对象的初始化和清理。

构造函数:函数名和类名相同,没有void,可以有参数,可以发生重载。

析构函数:~类名,不可以有参数,不能重载。

如果没有实现,编译器会自动帮我们实现。

构造函数的分类:

按照参数:1、无参数(默认构造),2、有参数

按照类型:拷贝构造函数(const Persion & P) 和 普通构造函数。

调用方式:1、括号法调用  。2、显示法调用

Persion p1 = Persion(100);   匿名对象

Persion p2 = 100;  

Persion p3 = p1;   隐式类型转换。

7、浅拷贝

   系统会提供默认拷贝构造,简单的值拷贝,如果属性里有指向堆空间数据,那么析构函数调用会释放堆空间两次,造成崩溃。

深拷贝

    自己实现拷贝构造函数,每一次都创建一个新的堆空间。

第三章

1、初始化列表

    Persion(int a, int b, int c) : m_A(a), m_B(b), m_C(c) {}

2、类对象作为类成员

    构造函数调用:从类内到类外

    析构函数调用:从类外到类内

3、explicit关键字,防止隐式类型转换

4、动态对象的创建 (堆区开辟)

    malloc 标准函数,不会调用构造函数,返回 void *

    free 不会调用析构

    new 运算符,默认调用构造函数,堆区开辟,返回相应类型的指针。通过new开辟数组,一定要提供默认构造函数,释放的时候 delete 后加 [] 。在栈上开辟的话,可以指定有参构造。

    delete 调用析构,当void * 接受new时不会调用析构函数。

第四章

1、静态成员变量 static

    在一个类中,若将一个成员变量声明为static类型,这就是静态成员变量,此时无论建立了多少个对象,都只共享一份数据。静态变量,在编译阶段就已经分配空间,对象都还没创建。

    1. 静态成员变量必须在类中声明定义,在类外初始化。
    2. 静态成员变量不属于某个对象,在为对象分配内存的时候也不包括静态成员变量。
    3. 静态数据成员可以通过类名或者对象名来引用。
    4. 也有访问权限,但是也是在类外初始化。

2、静态成员函数

在一个类中声明的函数前加static,也是共享一份内存,在编译阶段就已经分配空间。通过类名,对象调用。

  1. 不可以访问普通成员变量,可以访问静态成员变量。
  2. 也有访问权限。

单例模式

3、成员变量和成员函数分开存储

空类的大小是1,每一对象都要有一个独一无二的地址,char类型的维护这个地址。

非静态成员函数,不属于对象

静态成员变量,不属于对象

静态成员函数,不属于对象

只有非静态成员变量,才属于对象。

4、空指针调用成员函数

不涉及成员变量可以访问,如果用到了this 指针,要加this判断是否为null。

5、常函数

不允许修改this 指针指向的值。

Void fun() const {}

Mutable   // 强制修改符

常对象:常对象不允许调用普通成员函数修改对象属性。常对象可以调用常函数。

6、友元(好朋友)

  1. 友元函数:

在类中声明外部函数,前面用friend修饰,表示友元函数,之后就可以访问私有成员函数。

  1. 友元类:

在类中声明另外一个类作为该类的友元类,然后可以访问该类的私有成员属性。

Friend class 类名; // 单向的不可以传递

  1. 类成员函数作为友元函数:

Friend void GodGay::fun();

第五章

1、运算符重载

在c++中,定义一个处理类的新运算符,

Operator 运算符 (入参){}

注意:

<< 左移运算符不能写到成员函数中

第六章

1、继承

一个派生类继承了所有的基类方法,但下列情况除外:

  1. 基类的构造函数、析构函数和拷贝构造函数。
  2. 基类的重载运算符。
  3. 基类的友元函数。

当一个类派生自基类,该基类可以被继承为 public、protected 或 private 几种类型。继承类型是通过上面讲解的访问修饰符 access-specifier 来指定的。

我们几乎不使用 protected 或 private 继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:

  1. 公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
  2. 保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
  3. 私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。

构造和析构顺序

子类创建对象时,先调用父类的构造函数,然后再调用自身构造函数。

对象销毁时,析构调用刚好相反,先调用自身,然后再调用父类。

继承中的同名处理:

优先调用自身的属性和函数,如果想调用父类的,需要作用域运算符。

父类中的静态成员属性,可以被子类继承下来。

2、抽象类和虚函数

是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数,在父类中函数声明virtual,子类可以重写这个函数。

纯虚函数:

virtual int area() = 0;

如果父类中,出现纯虚函数,则子类中,必须要实现。

如何类中出现了纯虚函数,则不能实例化对象,称做抽象类。如果一个类继承了抽象类,必须实现纯虚函数。

3、虚析构

通过父类指针指向子类对象,导致释放不干净。

普通的析构,时不会去调用子类的析构函数,所以可能会导致 资源释放不干净。所以引入虚析构的概念。

在虚构函数前加上 virtual 关键字,后面就会调用子类的虚构函数。

纯虚析构:

Virtual ~animal() = 0;

把虚构函数声明为纯虚析构函数,类内声明,类外实现。

Note:如果类中的析构函数被声明纯虚析构函数,则类也是抽象类,不能进行实例化。

向下类型转换

Animal *an = new Animal;

Cat * cat = (Cat *) an;

父类指针强制转换为子类,cat的this寻址范围变大,实际的资源是父类an的,会产生指针调用越界,不安全!

向上类型转换

Cat *cat = new Cat;

Animal * an = (Animal *) cat;

子类指针强制转换成父类,子类an寻址范围变下,实际资源是cat的,this寻址范围变小,安全的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值