您的当前位置:首页C++ 基础

C++ 基础

2024-12-13 来源:哗拓教育

C++基础

1、C++对C的扩展

1.1程序设计方法的发展历程

面向过程的机构化程序设计方法

  • 设计思路

    – 自顶向下、逐步求精。采用模块分解与功能抽象,自顶向下、分而治之。

  • 程序结构

    – 按功能划分为若干个基本模块,形成一个树状结构。

    – 各模块间的关系尽可能简单,功能上相对独立;每一模块内部均是由顺序、选择和循环三种基本结构组成。

    – 其模块化实现的具体方法是使用子程序。

  • 优点:

    有效地将一个较复杂的程序系统设计任务分解成许多易于控制和处理的子任务,便于开发和维护。

  • 缺点:可重用性差、数据安全性差、难以开发大型软件和图形界面的应用软件

    – 把数据和处理数据的过程分离为相互独立的实体。

    – 当数据结构改变时,所有相关的处理过程都要进行相应的修改。

    – 每一种相对于老问题的新方法都要带来额外的开销。

    – 图形用户界面的应用程序,很难用过程来描述和实现,开发和维护也都很困难。

面向对象的方法

  • 将数据及对数据的操作方法封装在一起,作为一个相互依存、不可分离的整体——对象。
  • 对同类型对象抽象出其共性,形成类。
    • 类通过一个简单的外部接口,与外界发生关系。
    • 对象与对象之间通过消息进行通信。

面向对象的基本概念

对象

  • 一般意义上的对象:

– 是现实世界中一个实际存在的事物。

– 可以是有形的(比如一辆汽车),也可以是无形的(比如一项计划)。

– 是构成世界的一个独立单位,具有

​ – 静态特征:可以用某种数据来描述

​ – 动态特征:对象所表现的行为或具有的功能

  • 面向对象方法中的对象:

– 是系统中用来描述客观事物的一个实体,它是用来构成系统的一个基本单位。对象由一组属性和一组行为构成。

– 属性:用来描述对象静态特征的数据项。

– 行为:用来描述对象动态特征的操作序列。

  • 分类——人类通常的思维方法

  • 分类所依据的原则——抽象

    – 忽略事物的非本质特征,只注意那些与当前目标有关的本质特征,从而找出事物的共性,把具有共同性质的事物划分为一类,得出一个抽象的概念。

    – 例如,石头、树木、汽车、房屋等都是人们在长期的生产和生活实践中抽象出的概念。

    • 面向对象方法中的"类"

    – 具有相同属性和服务的一组对象的集合

    – 为属于该类的全部对象提供了抽象的描述,包括属性和行为两个主要部分。


    类与对象的关系:
    犹如模具与铸件之间的关系,一个属于某类的对象称为该类的一个实例。

封装

也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

  • 把对象的属性和服务结合成一个独立的系统单元。

  • 尽可能隐蔽对象的内部细节。对外形成一个边界(或者说一道屏障),只保留有限的对外接口使之与外部发生联系。

    • 继承对于软件复用有着重要意义,是面向对象技术能够提高软件开发效率的重要原因之一。

    • 定义:特殊类的对象拥有其一般类的全部属性与服务,称作特殊类对一般类的继承。

    • 例如:将轮船作为一个一般类,客轮便是一个特殊类。

    多态

    多态是指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或行为在一般类及其各个特殊类中具有不同的语义。

面向对象的软件工程

  • 面向对象的软件工程是面向对象方法在软件工程领域的全面应用。它包括:

– 面向对象的分析(OOA)

– 面向对象的设计(OOD)

– 面向对象的编程(OOP)

– 面向对象的测试(OOT)

– 面向对象的软件维护(OOSM)

总结:

面向过程程序设计:数据结构 + 算法

主要解决科学计算问题,用户需求简单而固定

特点:

分析解决问题所需要的步骤

利用函数实现各个步骤

依次调用函数解决问题

问题:

软件可重用性差

软件可维护性差

构建的软件无法满足用户需求

面向对象程序设计:由现实世界建立软件模型

将现实世界中的事物直接映射到程序中,可直接满足用户需求

特点:

直接分析用户需求中涉及的各个实体

在代码中描述现实世界中的实体

在代码中关联各个实体协同工作解决问题

优势:

构建的软件能够适应用户需求的不断变化

直接利用面向过程方法的优势而避开其劣势

1.2 C语音和C++语音的关系

  1. C语言是在实践的过程中逐步完善起来的

​ 没有深思熟虑的设计过程

​ 使用时存在很多“灰色地带”

​ 残留量过多低级语言的特征

​ 直接利用指针进行内存操作

  1. C语言的目标是高效

    最终程序执行效率的高效

  2. 当面向过程方法论暴露越来越多的缺陷的时候,业界开始考虑在工程项目中引入面向对象的设计方法,而第一个需要解决的问题就是:高效的面向对象语言,并且能够兼容已经存在的代码。

    C语言 + 面向对象方法论===》Objective C /C++

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

    C++是C语言的加强,是一种更好的C语言

    C++是以C语言为基础的,并且完全兼容C语言的特性

  4. 学习C++并不会影响原有的C语言知识,相反会根据加深对C的认知;

    学习C++可以接触到更多的软件设计方法,并带来更多的机会。

    1) C++是一种更强大的C,通过学习C++能够掌握更多的软件设计方法

    2) C++是Java/C#/D等现代开发语言的基础,学习C++后能够快速掌握这些语言

    3)C++是各大知名软件企业挑选人才的标准之一

图1-1.jpg

1.3 C++对C的加强

1.3.1 namespace命名空间

  1. C++命名空间基本常识

所谓namespace,是指标识符的各种可见范围。C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。

一 :<iostream>和<iostream.h>格式不一样,前者没有后缀,实际上,在你的编译器include文件夹里面可以看到,二者是两个文件,打开文件就会发现,里面的代码是不一样的。后缀为.h的头文件c++标准已经明确提出不支持了,早些的实现将标准库功能定义在全局空间里,声明在带.h后缀的头文件里,c++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。因此,

1)当使用<iostream.h>时,相当于在c中调用库函数,使用的是全局命名空间,也就是早期的c++实现;

2)当使用<iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。

二: 由于namespace的概念,使用C++标准程序库的任何标识符时,可以有三种选择:

1、直接指定标识符。例如std::ostream而不是ostream。完整语句如下:std::cout << std::hex << 3.4 << std::endl;

2、使用using关键字。 usingstd::cout; using std::endl; using std::cin; 以上程序可以写成 cout<< std::hex << 3.4 << endl;

3、最方便的就是使用usingnamespace std; 例如: using namespace std;这样命名空间std内定义的所有标识符都有效(曝光)。就好像它们被声明为全局变量一样。那么以上语句可以如下写: cout <<hex << 3.4 << endl;因为标准库非常的庞大,所以程序员在选择的类的名称或函数名 时就很有可能和标准库中的某个名字相同。所以为了避免这种情况所造成的名字冲突,就把标准库中的一切都被放在名字空间std中。但这又会带来了一个新问题。无数原有的C++代码都依赖于使用了多年的伪标准库中的功能,他们都是在全局空间下的。所以就有了<iostream.h> 和<iostream>等等这样的头文件,一个是为了兼容以前的C++代码,一个是为了支持新的标准。命名空间std封装的是标准程序库的名称,标准程序库为了和以前的头文件区别,一般不加".h"

2.C++命名空间定义及使用语法

/* 在C++中,名称(name)可以是符号常量、变量、宏、函数、结构、枚举、类和对象等等。为了避免,在大规模程序的设计中,以及在程序员使用各种各样的C++库时,这些标识符的命名发生冲突, 标准C++引入了关键字namespace(命名空间/名字空间/名称空间/名域),可以更好地控制标识符的作用域。 */
/* std是c++标准命名空间,c++标准程序库中的所有标识符都被定义在std中,比如标准库中的类iostream、vector 等都定义在该命名空间中,使用时要加上using声明(using namespace std) 或using指示(如std::string、 std::vector<int>). */
/* C中的命名空间 在C语言中只有一个全局作用域 C语言中所有的全局标识符共享同一个作用域 标识符之间可能发生冲突 C++中提出了命名空间的概念 命名空间将全局作用域分成不同的部分 不同命名空间中的标识符可以同名而不会发生冲突 命名空间可以相互嵌套 全局作用域也叫默认命名空间 */
/* C++命名空间的定义: namespace name { … } */
/* C++命名空间的使用: 使用整个命名空间:using namespace name; 使用命名空间中的变量:using name::variable; 使用默认命名空间中的变量:::variable 默认情况下可以直接使用默 认命名空间中的所有标识符 */
  1. C++命名空间编程实践
namespace NameSpaceA
{   
    int a = 0;
}
    
namespace NameSpaceB
{   
    int a = 1;

    namespace NameSpaceC
    {
        struct Teacher
        {
            char name[10];
            int age;
        };
    }
}

int main()
{
    using namespace NameSpaceA;
    using NameSpaceB::NameSpaceC::Teacher;

    printf("a = %d\n", a);
    printf("a = %d\n", NameSpaceB::a);

NameSpaceB::NameSpaceC::Teacher t2
    Teacher t1 = {"aaa", 3};

    printf("t1.name = %s\n", t1.name);
    printf("t1.age = %d\n", t1.age);

    system("pause");
    return 0;
}

4 .结论

3) C++命名空间的定义: namespacename { … }

4) using namespace NameSpaceA;

5) namespce定义可嵌套。

1.3.2“实用性”增加

#include "iostream"
using namespace std;

//C语言中的变量都必须在作用域开始的位置定义!!
//C++中更强调语言的“实用性”,所有的变量都可以在需要使用时再定义。

int main11()
{
    int i = 0;

    printf("ddd");
    int k;
    system("pause");
    return 0;
}

1.3.3register关键字增强

//register关键字 请求编译器让变量a直接放在寄存器里面,速度快
//在c语言中 register修饰的变量 不能取地址,但是在c++里面做了内容

/*
//1
register关键字的变化
register关键字请求“编译器”将局部变量存储于寄存器中
C语言中无法取得register变量地址
在C++中依然支持register关键字
C++编译器有自己的优化方式,不使用register也可能做优化
C++中可以取得register变量的地址
//2
C++编译器发现程序中需要取register变量的地址时,register对变量的声明变得无效。

//3
早期C语言编译器不会对代码进行优化,因此register变量是一个很好的补充。
*/

int main22()
{
    register int a = 0; 

    printf("&a = %x\n", &a);

    system("pause");
    return 0;
}

1.3.4变量检测增强

/*
在C语言中,重复定义多个同名的全局变量是合法的
    在C++中,不允许定义多个同名的全局变量
C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上
int g_var;
int g_var = 1;

C++直接拒绝这种二义性的做法。
*/

1.3.5struct类型加强

struct类型的加强:

C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型

C++中的struct是一个新类型的定义声明

struct Student
{
    char name[100];
    int age;
};

int main(int argc, char *argv[])
{
    Student s1 = {"wang", 1};
    Student s2 = {"wang2", 2};    
    return 0;
}

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

/*
C++中所有的变量和函数都必须有类型
    C语言中的默认类型在C++中是不合法的


函数f的返回值是什么类型,参数又是什么类型?
函数g可以接受多少个参数?
*/

//更换成.cpp试试

f(i)
{
    printf("i = %d\n", i);

}

g()
{
    return 5;
}

int main(int argc, char *argv[])
{

    f(10);

    printf("g() = %d\n", g(1, 2, 3, 4, 5));


    getchar();  
    return 0;
}

总结:

/*

在C语言中

           intf(    );表示返回值为int,接受任意参数的函数

           intf(void);表示返回值为int的无参函数

           在C++中

           intf(  );和int f(void)具有相同的意义,都表示返回值为int的无参函数

*/                              

C++更加强调类型,任意的程序元素都必须显示指明类型

1.3.2-1.3.6属于语法级别的增强。

1.3.7新增Bool类型关键字

/*
C++中的布尔类型
    C++在C语言的基本类型系统之上增加了bool
    C++中的bool可取的值只有true和false
    理论上bool只占用一个字节,
    如果多个bool变量定义在一起,可能会各占一个bit,这取决于编译器的实现

    true代表真值,编译器内部用1来表示
    false代表非真值,编译器内部用0来表示

    bool类型只有true(非0)和false(0)两个值
    C++编译器会在赋值时将非0值转换为true,0值转换为false
*/
int main(int argc, char *argv[])
{
    int a;
    bool b = true;
    printf("b = %d, sizeof(b) = %d\n", b, sizeof(b));

    b = 4;
    a = b;
    printf("a = %d, b = %d\n", a, b);

    b = -4;
    a = b;
    printf("a = %d, b = %d\n", a, b);

    a = 10;
    b = a;
    printf("a = %d, b = %d\n", a, b);

    b = 0;
    printf("b = %d\n", b);

    system("pause");
    return 0;
}

1.3.8三目运算符功能增强

三目运算符在C和C++编译器的表现

int main()
{
    int a = 10;
    int b = 20;

    //返回一个最小数 并且给最小数赋值成3
    //三目运算符是一个表达式 ,表达式不可能做左值
    (a < b ? a : b )= 30;

    printf("a = %d, b = %d\n", a, b); 

    system("pause");

    return 0;
}

2结论

1)C语言返回变量的值 C++语言是返回变量本身

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

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

2)注意:三目运算符可能返回的值中如果有一个是常量值,则不能作为左值使用(a < b ? 1 :b )= 30;

3)C语言如何支持类似C++的特性呢?

====>当左值的条件:要有内存空间;C++编译器帮助程序员取了一个地址而已

思考:如何让C中的三目运算法当左值呢?

1.4 C/C++中的const

1 const基础知识(用法、含义、好处)


int main()
{
const int a;
int const b;

const int *c;
int * const d;
const int * const e ;

return 0;
}

Int func1(const )
初级理解:const是定义常量==》const意味着只读
含义:
//第一个第二个意思一样 代表一个常整形数
//第三个 c是一个指向常整形数的指针(所指向的内存数据不能被修改,但是本身可以修改)
//第四个 d 常指针(指针变量不能被修改,但是它所指向内存空间可以被修改)
//第五个 e一个指向常整形的常指针(指针和它所指向的内存空间,均不能被修改)
Const好处
//合理的利用const,
//1指针做函数参数,可以有效的提高代码可读性,减少bug;
//2清楚的分清参数的输入和输出特性
int setTeacher_err( const Teacher *p)
Const修改形参的时候,在利用形参不能修改指针所向的内存空间

2 C中“冒牌货”

int main()
{
    const int a = 10;
    int *p = (int*)&a; 
    printf("a===>%d\n", a);
    *p = 11;
    printf("a===>%d\n", a);

    printf("Hello......\n");
    return 0;
}
解释:
C++编译器对const常量的处理
当碰见常量声明时,在符号表中放入常量 =问题:那有如何解释取地址
编译过程中若发现使用常量则直接以符号表中的值替换
编译过程中若发现对const使用了extern或者&操作符,则给对应的常量分配存储空间(兼容C)
?联想: int &a = 1(err) & const int &a = 10(ok)?

C++中const符号表原理图

图1-2.png

注意:

C++编译器虽然可能为const常量分配空间,但不会使用其存储空间中的值。

结论:
C语言中的const变量
C语言中const变量是只读变量,有自己的存储空间
C++中的const常量
可能分配存储空间,也可能不分配存储空间
当const常量为全局,并且需要在其它文件中使用
当使用&操作符取const常量的地址

3 const和#define相同之处

//练习 解释为什么
//#define N 10 
int main()
{
    const int a = 1; 
    const int b = 2; 
    int array[a + b ] = {0};
    int i = 0; 
        
    for(i=0; i<(a+b); i++)
    {
        printf("array[%d] = %d\n", i, array[i]);
    }
    
    
    getchar();
    
    return 0;
}

C++中的const修饰的,是一个真正的常量,而不是C中变量(只读)。在const修饰的常量编译期间,就已经确定下来了。

4 const和#define的区别

/*对比加深
C++中的const常量类似于宏定义
const int c = 5; ≈ #define c 5
C++中的const常量与宏定义不同
const常量是由编译器处理的,提供类型检查和作用域检查 
宏定义由预处理器处理,单纯的文本替换
//在func1定义a,在func2中能使用吗?
//在func1中定义的b,在func2中能使用吗?
*/

void fun1()
{
    #define a 10
    const int b = 20;
    //#undef a  # undef
}

void fun2()
{
    printf("a = %d\n", a);
    //printf("b = %d\n", b);
}

int main()
{
    fun1();
    fun2();
    return 0;
}


5 结论

C语言中的const变量

C语言中const变量是只读变量,有自己的存储空间

C++中的const常量

可能分配存储空间,也可能不分配存储空间

当const常量为全局,并且需要在其它文件中使用,会分配存储空间

当使用&操作符,取const常量的地址时,会分配存储空间

当const int &a = 10; const修饰引用时,也会分配存储空间

显示全文