c++

C++

1. C++概述

1.1 C++简介

c++是c的扩展,是c的超集。任何有效的c程序都是有效的c++程序。

c++可以使用已有的c程序库。

c++语言在c语言的基础上添加了面向对象编程和泛型编程的支持。

c++继承了c语言高效、简洁、快速和可移植的传统(特性)

C++编程方式:

  • c的面向过程编程
  • c++的面向对象编程
  • c++模板的泛型编程

C语言和C++语言的关系:

c++语言实在c语言的基础上,添加了面向对象、模板等现代程序设计语言的特性而发展起来的。两者无论是从语法规则上。还是从运算符的数量和使用上,都非常相似,所以我们常常将这两门语言统称为“c/c++”

C语言和C++并不是对立的竞争关系:

1.c++是c语言的加强,是一种更好的c语言
2.c++是以c语言为基础的,并且完全兼容c语言的特性

1.2 可移植性和标准

可移植性:开发的c/c++的源代码,可以在任何安装c/c++编译器的操作系统,可以重新编译,即可运行。

标准:

  • ANSI/ISO C++
  • ISO/IEC 14882:1998,简称c++98
    • 已有的c++特性
    • 对语言进行了扩展,添加了异常、运行阶段类型识别(RTTI)、模板和标准模板库(STL)
  • ISO/IEC 14482:2003,只是修复c++98的bug,没有大的改动。因此c++98也称之为c++98/c++2003
  • ISO/IEC 14482:2011:c++11

2. C++初始

2.1分析C++的helloworld

#include <iostream>

using namespace std;

int main()
{
    cout << "Hello World!" << endl;
    return 0;
}

第一行:引入iostream头文件,此文件包含std命名空间,和标准的输入和输出

第二行:using namespace std;使用标准的命名空间,命名空间中定义标准的变量

第四行:cout输出对象,是std命名空间的,也可以写成std::cout,cout和<<运算符组合使用,表示输出什么内容,如"Hello World!"endl表示换行符

image-20231023082809561

将main.cpp的文件内容,修改如下:

#include <stdio.h>
int main()
{
    printf("Hello World!");
    return 0;
}

代码可以正常运行,说明c++兼容c的语法

2.2 面向过程和面向对象

2.2.1 面向过程

面向过程编程思想的核心:功能分解,自顶向下,逐层细化(程序=数据结构+算法)

面向过程编程语言存在的主要缺点是不符合人的思维习惯,而是要用计算机的思维方式去处理问题,而且面向过程编程语言重用性低、维护困难

2.2.2 面向对象

面向对象编程(Object-Oriented Programming)以下简称 OOP 。

在面向对象中,算法与数据结构被看做是一个整体,称作对象,现实世界中任何类的对象都具有一定的熟悉和操作,也总能用数据结构与算法两者合一地来描述,所以可以用下面的等式来定义对象和程序:

对象 = 算法(方法或功能函数) + 数据结构(数组、结构体...)
程序 = 对象 + 对象 + ...

面向对象编程思想的核心:应对变化、提高复用

2.2.3 面向对象的三大特征

  • 封装:可以将客观的事务抽象为类,类中封装一些数据(属性-特征)和方法(行为),可以根据需要设置数据或方法的访问权限,对于一些重要的数据设置为不可访问。
  • 继承:继承所表达的是类之间相关的关系,这种关系使得对象可以继承另外一类对象的特征和能力,继承的作用:避免公用代码的重复开发,减少代码和数据冗余。
  • 多态:多态可以简单概括为"一个接口,多种方法",字面意思为多种形态。多用于描述一个对象的多种形态,使用多态性必须具有继承和重写方法的前提。

3. C++对C的扩展

3.1 ::作用域运算符

可用::对被屏蔽的同名的全局变量进行访问

3.2 名字控制

在大的工程中,存在多个源文件或类,所以可能存在重名的情况。在C++提供不同方式,使得同一个名字可以具有不同的数据或功能

3.2.1 c++命名空间(namespace)

为了避免,在大规模程序的设计中,以及在程序员使用各种各样的c/c++库时,这些标识符的命名发生冲突,标准c++引入关键字namespace(命名空间/名字空间/名称空间),可以更好地控制标识符的作用域

3.2.2 namespace用法:

  • 命名空间只能全局范围内定义,不能在局部定义

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

  • 声明和实现可分离

  • 无名的命名空间只能在当前文件中使用

  • 命名空间可以存在别名

  • 定义namespace的语法:

    namespace [名称]
    {
        成员的声明,可以具有初始化的值;
        [
            内部嵌套namespace{};
        ]
        [声明成员函数]
        [定义成员函数]
    }
    
    //实现namespace中声明的函数
    函数返回值类型 命名空间的名称::声明的函数名(形参列表){
        
    }
    

    【无命名空间】

    无名命名空间,意味着命名空间中的标识符只能在本文件内访问,相当于给这个标识符加上了static,使得其可以作为内部连接
    

3.2.3 using声明

using声明可使得指定的标识符(函数、变量、结构体、枚举、类)可用

语法:

using 命名空间的名称::成员名; 当前位置向下,可以直接使用成员名,即为命名空间的成员

【注意】使用了命名空间之后,可能存在名称冲突。平时使用时注意using和其它同名标识符先后顺序。

using声明碰到函数重载:using一次函数名,既可以将所有的相同名的重载函数都引入

3.2.4 using编译指令

using编译指令使整个命名空间标识符可用

【注】使用using声明或using编译指令会增加命名冲突的可能性。也就是说,如果有名称空间,并在代码中使用作用域解析运算符,则不会出现二义性。

语法:

using namespace 命名空间的名称; 当前位置向下,可以直接访问命名空间中所有的成员

3.2.5 命名空间使用

需要记住的关键问题是当引入一个全局的using编译指令时,就为改文件打开了该命名空间,它不会影响任何其他的文件,所以可以在每一个实现文件中调整对命名空间的控制

如果发现某一个实现文件中有太多的using指令或声明而产生的命名冲突,就要对该文件做个简单的改变,通过明确的限定或者using声明来消除名字冲突,这样不需要修改其他的实现文件。

3.3 全局变量检测增强

在C++中全局变量无论是声明还是定义,只能出现一次。

因此,在c++中定义全局变量时,无初始化值时,默认值为0。

3.4 C++中所有的变量和函数都必须有类型

C的自定义函数时,形参变量可以没有数据类型,即为任意类型

c++中,函数的形参变量必须指定类型。

3.5 更严格的类型转换

在C++中, 不同类型的变量之间赋值时,需要明确的类型转换。

3.6 struct类型加强

在C++中,定义结构体变量时,不用加struct。

3.7 新增bool 类型关键字

bool 类型只有两个值,true(非0值),false(0 值)

bool 类型占 1 个字节大小(操作系统最小处理数据单位是字节)。

3.8 三目运算符功能增强

C中三目运算表达返回是变量的值, 而c++中,三目运算表达式返回是变量。

3.9 C/C++中的const

const修饰的变量,只能读取,不能修改其值。

C/C++中 const 的区别:

原则上:c中的const变量,不能做为数组的个数使用, 因为数组分配的空间可能发生变化(扩大,缩小)。

gcc 99/g++11编译器: const变量可以作为数组的个数使用。

C中的const变量,在定义时,则会在内存中创建空间, 而c++不会创建,只有取一个 const 地址, 或者把它定义为 extern,则会为该 const 创建内存空间。

在 c++中,出现在所有函数之外的 const 作用于整个文件(也就是说它在该文件外不可见),默认为内部连接,c++中其他的标识符一般默认为外部连接(指向是常量区)。

默认情况下,const初始化值为常量,不会开辟空间,只是存储在符号表中。如果const变量初始化值为一个变量时,则会在内存中开辟空间

3.10 const和#define的区别

1)const变量有数据类型,而#define宏无数据类型

调用重载的函数时,传入const变量时正确的,而传入宏,是无法确认调用函数的入口

2)const变量具有作用域,而#define宏从定义开始到文件结束都是有效的

3.11 引用

引用相当于指针,在向函数传递地址时,可以使用指针,也可以使用引用。引用是c++对c的重要扩充

3.11.1 基本用法

普通变量的用法:为变量起别名,变量的引用名即和变量名操作同一个内存空间

定义引用变量时,必须给初始化值,另外,定义之后引用不能再引用其它的变量。初始值不是NULL。

引用数组的正确方式:不能直接引用数组(int &p=arr)

3.11.2 函数的参数引用

形参可以是引用,声明方式:数据类型 &形参名

函数的返回值也可以是一个引用,返回的变量不能是局部变量

如果函数返回值作为赋值语句的左值,则必须返回引用

数组引用作为函数的参数,数组名本身就是一个地址,无需再按数组的引用定义方式来定义形参

3.11.3 引用的本质

引用的本质是指针常量,初始化时必须给定初始值,因为指针不能修改

常量指针和指针常量的区别

常量指针:const int *p = &a; const修饰是*p,*p只读,p读写
指针常量:int * const p = &a; const修饰是p,p只读,*p读写
常量指针常量: const int * const p = &a; *p只读,p只读

3.11.4 指针的引用

为指针起个别名,表示为指针的指针

用法:数据类型*& 变量名=指针变量名

3.11.5 常量引用

用法:const 数据类型 & 变量名 = 其它变量或常量

【注意】

1)一般的引用不能赋值常量(字面量),但是const引用可以赋值常量

2)const引用不能修改内容(数据)

3.12 内联函数

定义函数的前面添加了inline关键字,则此函数为内联函数

内联函数只能在当前文件中使用,相当于函数前面加static

内联函数一般用于替换有参的宏,有参宏经常会出错,而且参数是无数据类型。

每一次使用内联函数时,都会像有参宏一样,展开一次(内联函数不入栈,运行效率高)

内联函数为了继承宏函数的效率,没有函数调用时的开销,然后又可以像普通函数那样使用,每次使用时都会进行参数,返回值类型的安全检查,又可以作为成员函数。

内联函数作为类的成员函数时,可以访问私有成员(数据)

内联函数的声明和定义必须在一起,否则取消内联函数性质

【说明】类中所有函数,编译器默认都是内联函数。inline修饰的函数是否为内联函数,取决于编译器。对于非inline修饰的函数,也有可能转成内联函数(体积小、功能简单的函数)。

内联函数使用时的注意事项:

1)不能存在任何形式的循环语句
2)不能存在过多的条件判断语句
3)函数体不能过于庞大
4)不能对函数进行取址操作

3.13 函数的默认值参数

c++的函数在声明时,可以设置形参的默认值,在调用函数时,形参位置没有指定实参数据时,则使用默认值

【注意】函数的默认参数从左向右,如果一个参数设置了默认参数,那么这个参数之后的参数都必须设置默认参数,如果函数声明和函数定义分开写,函数声明和函数定义不能同时设置默认参数。

3.14 函数的占位参数

c++在声明函数时,可以设置占位参数。占位参数只有参数类型声明,而没有参数名。一般情况下,在函数体内部无法使用占位参数。占位参数也可以设置默认值。

【注意】调用函数时,占位参数也需要传值

3.15 函数重载和extern"c"

1.c++支持函数的重载特性,函数重载即与函数名和参数列表相关,与函数的返回值无关。

存在多个函数名相同、参数列表不同的情况时,称之为函数重载

参数列表不同:个数不同,个数相同时类型不同或顺序不同

void f(int a);
void f(int a, int b); // f(int,int)
void f(double a,int b);
void f(int a, double b);
// void f(int b, int a); 重载检查按参数类型不同查找,f(int, int) 上面已声明了,不能再次声明。

2.由于c++可以使用c的模块中函数,当c++整个工程编译时,可能会将使用c语言编写的函数名编译成c++规则的函数名(定义的函数名前随机添加新的名称),链接程序时,可能会找不到目标函数,因此采用extern "C"解决。

posted @ 2023-11-22 10:13  常羲和  阅读(58)  评论(0)    收藏  举报
// 侧边栏目录