C++【2】(C++基本概念)

273 阅读8分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

一、为什么学习C++

C++是C语言的升级版,在C语言的基础上添加了面向对象的思想,C++既可以底层编程,也可以图形界面编程,也可以数据处理,因为是面向对象的编程,所以在写代码时大大提高了效率。

二、相关概念

C语言是面向过程的语言,C++是面向对象的语言

  • 面向过程:编程思想注重于过程,意味着大大小小的功能都需要去实现
  • 面向对象:编程思想注重于结果,在完成一个大的项目的时候,小的功能基本都已经实现了,所以只需要进行调用就可以实现大的功能,所以便于程序员开发。它的主要功能是可以更方便得编写出好程序,让每个程序员更加快乐”。

三、C++重要的概念

3.1 面向过程

面向过程是一种以过程为中心的编程思想。

通过分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。

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

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

3.2 面向对象

面向对象编程(Object-Oriented Programming)简称 OOP 技术,是开发计算机应用程序的一种新方法、新思想。过去的面向过程编程常常会导致所有的代码都包含在几个模块中,使程序难以阅读和维护。在做一些修改时常常牵一动百,使以后的开发和维护难以为继。而使用 OOP 技术,常常要使用许多代码模块,每个模块都只提供特定的功能,它们是彼此独立的,这样就增大了代码重用的几率,更加有利于软件的开发、维护和升级。

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

  • 对象 = 算法 + 数据结构
  • 程序 = 对象 + 对象 + ……

从上面的等式可以看出,程序就是许多对象在计算机中相继表现自己,而对象则是一个个程序实体。 面向对象编程思想的核心:应对变化,提高复用

3.3 类和对象

类:类似于结构体,一个类转给你函数和变量都可以定义 例如数据结构中的链表,C语言是需要写一个程序来实现和调用, C++可以直接将所有的变量和功能函数都定义在一个类中,这样调 用起来更加方便

对象:类实例化的对象,类似于结构体变量,所以对象就是类定义的变量

3.4 面向对象语言三要素

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

类将成员变量和成员函数封装在类的内部,根据需要设置访问权限, 通过成员函数管理内部状态。

C语言中结构体内部不可以定义函数,但是在C++的结构体或者类重视可以定义函数的

==继承==:继承所表达的是类之间相关的关系,这种关系使得对象可以继承另 外一类对象的特征和能力。

继承的作用:避免公用代码的重复开发,减少代码和数据冗余

一个类可以基础另一个类中几乎所有的成员函数和成员变量,这样大大提高了代码的复用性

==多态==:多态性可以简单地概括为“一个接口,多种方法”,字面意思为多 种形态。程序在运行时才决定调用的函数,它是面向对象编程领 域的核心概念。

函数调用之前,一般在编译阶段函数的地址就已经确定了, 称之为静态多态,如果是在代码运行的时候才确定,称之为动态多态

静态多态:函数重载、运算符重载

动态多态:虚函数、纯虚函数、虚析构函数、纯虚析构函数

四、域解析符

#include <iostream>

using namespace std;

int num = 100;

void test1()
{
    cout << "num = " << num << endl;

    int num = 888;
    cout << "num = " << num << endl;

    //:: :域解析符,主要用于操作全局定义的变量或者类或者函数等等
    cout << "num = " << ::num << endl;
    ::num = 999;
    cout << "num = " << ::num << endl;
}

int main()
{
	test1();

	return 0;
}

五、命名空间

  1. 主要就是为了防止多人一起协同写代码时出现重名的情况
  2. 命名空间里面可以存放几乎所有全局的东西,例如全局变量、函数、结构体、类、宏定义、取别名

5.1 定义一个命名空间

注意:**定义之后不需要加==;==**内部的变量空间都已经开辟了,不是在定义数据类型

namespace zhangsan {
    int num = 333;
    void myfun()
    {
        cout << "nihao, beijing" << endl;
    }
}

5.2 命名空间的基本使用

命名空间里面的成员需要命名空间的名字通过域解析符来操作

void test1()
{
    cout << "zhangsan: num = " << zhangsan::num << endl;
    cout << "lisi: num = " << lisi::num << endl;

    zhangsan::myfun();
    lisi::myfun();
}

如果在一个函数里面要经常使用某个命名空间内的成员,可以通过using关键字标识,这样操作这个成员的时候就不需要命名空间的名字来访问了;在一个函数里面如果已经对某一个命名空间中的成员通过using标识,就不能在对同名的其他命名空间的成员进行标识

using zhangsan::num;

cout << "zhangsan: num = " << num << endl;
num = 1000;

如果在一个代码中都要使用某一个命名空间中的成员,可以通过using标识整个命名空间,这样里面所有的成员操作的时候都不需要通过命名空间来访问了,一般都放在最上面

#include <iostream>//程序与外部的通信

using namespace std;

namespace zhangsan {
    int num = 333;
    void myfun()
    {
        cout << "nihao, beijing" << endl;
    }
}

namespace lisi {
    int num = 888;
    void myfun()
    {
        cout << "欢迎来到华清远见学习" << endl;
    }
}

//命名空间的基本使用
//命名空间里面的成员需要命名空间的名字通过域解析符来操作
void test1()
{
    cout << "zhangsan: num = " << zhangsan::num << endl;
    cout << "lisi: num = " << lisi::num << endl;

    zhangsan::myfun();
    lisi::myfun();
}

void test2()
{
    //如果在一个函数里面要经常使用某个命名空间内的成员
    //可以通过using关键字标识,这样操作这个成员的时候就
    //不需要命名空间的名字来访问了
    using zhangsan::num;

    cout << "zhangsan: num = " << num << endl;
    num = 1000;
    cout << "zhangsan: num = " << num << endl;

    //在一个函数里面如果已经对某一个命名空间中的成员通过using标识,
    //就不能在对同名的其他命名空间的成员进行标识
    //using lisi::num;
    cout << "lisi: num = " << lisi::num << endl;

    using lisi::myfun;
    myfun();
}

//如果在一个代码中都要使用某一个命名空间中的成员,
//可以通过using标识整个命名空间,这样里面所有的成员
//操作的时候都不需要通过命名空间来访问了,一般都放在最上面
using namespace zhangsan;

void test3()
{
    cout << num << endl;
    myfun();

    zhangsan::myfun();
    lisi::myfun();
}

int main()
{
    test3();
    return 0;
}

六、C++中的结构体的使用

6.1 C语言中的结构体

#include <stdio.h>

//定义一个结构体
struct Chinese{
    char name[32];

//C语言结构体不允许内部定义函数
#if 0
    void myfun()
    {
        printf("hello world\n");
    }
#endif
};

struct USA{
    char name[32];
};

void IntroduceChinese(struct Chinese *ch)
{
    printf("%s是一个中国人\n", ch->name);
}

void IntroduceUSA(struct USA *u)
{
    printf("%s is a foreigner\n", u->name);
}

void test1()
{
    //定义结构体变量
    //C语言定义结构体变量时必须加struct
    struct Chinese ch = {"张三"};
    struct USA u  = {"Bob"};

    IntroduceChinese(&ch);
    IntroduceUSA(&u);
    
    //C语言中的结构体没有封装性,所以函数无法再结构体中定义,
    //意味着这个函数谁都可以调用,有时候就会产生歧义
    IntroduceChinese(&u);
}

int main()
{
    test1();

    return 0;
}

6.2 C++中的结构体

#include <iostream>

using namespace std;

struct Chinese{
    char name[32];

    //C++中的结构体内部是可以定义函数的
#if 0
    void fun()
    {
        cout << "hello world" << endl;
    }
#endif

    void Introduce()
    {
        printf("%s是一个中国人\n", name);
    }
};

struct USA{
    char name[32];

    void Introduce()
    {
        printf("%s is a foreigner\n", name);
    }
};

void test1()
{
    //C++中结构体变量定义的时候可以不用加struct
    Chinese ch = {"张三"};
    USA u = {"Bob"};
    
    //C++中结构体具有封装性,一定程度上保护了自己的成员
    //意味着有些函数只允许自己使用,不允许其他结构体的变
    //量操作
    ch.Introduce();
    u.Introduce();
}

int main()
{
    test1();
    return 0;
}

6.3 区别对比

  1. C语言结构体不允许内部定义函数《===》C++中的结构体内部是可以定义函数的
  2. C语言定义结构体变量时必须加struct《===》C++中结构体变量定义的时候可以不用加struct
  3. C语言中的结构体没有封装性,所以函数无法再结构体中定义,意味着这个函数谁都可以调用,有时候就会产生歧义《===》C++中结构体具有封装性,一定程度上保护了自己的成员,意味着有些函数只允许自己使用,不允许其他结构体对变量操作

七、bool类型

#include <iostream>

using namespace std;

//C++支持bool类型,可以赋值为true或者false,大小占一个字节
int main()
{
    bool a = true;
    cout << "a = " << a << endl;

    bool b = false;
    cout << "b = " << b << endl;

    cout << "sizeof(a) = " << sizeof(a) << endl;

    return 0;
}

八、C++中的标准输入输出

#include <iostream>

using namespace std;

//标准输出:cout
//cout不是一个函数,是类实例化的对象
void test1()
{
    int a = 333;
    char b = 'w';
    char c[] = "hello world";
    float d = 3.1415926f;

    cout << "a = " << a << endl;
    //输出十六进制
    cout << hex << a << endl;
    //输出八进制
    cout << oct << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;
    cout << "d = " << d << endl;
}

//标准输入:cin
//cin是一个类实例化的对象
void test2()
{
//    int a;
//    cin >> a;
//    cout << "a = " << a << endl;

    int a, b, c;
    cin >> a >> b >> c;

    cout << "a = " << a;
    cout << ", b = " << b;
    cout << ", c = " << c << endl;
}

int main()
{
    test2();

    return 0;
}

九、C++中的const

9.1 C语言的const

  1. const修饰全局变量:不管用哪种方式都无法修改全局变量的值,只能使用不能修改
  2. const修饰局部变量:无法通过变量本身直接修改,但是可以通过指针修改地址里面的内容
  3. const修饰指针变量的类型,无法通过指针变量修改地址里面的内容
  4. const修饰指针变量,无法修改指针变量保存的地址
#include <stdio.h>

//const修饰全局变量
//不管用哪种方式都无法修改全局变量的值,只能使用不能修改
const int a = 888;
void test1()
{
    printf("a = %d\n", a);

    //a = 666;//这样肯定不行
    //printf("a = %d\n", a);

    //int *p = &a;
    //*p = 666;
    //printf("a = %d\n", a);//程序异常结束,因为信号
}

//const修饰局部变量
//无法通过变量本身直接修改,但是可以通过指针修改地址里面的内容
void test2()
{
    const int num = 100;
    printf("num = %d\n", num);

    //num = 200;//只读,不能改
    //printf("num = %d\n", num);

    int *p = &num;//通过地址修改了
    *p = 300;
    printf("num = %d\n", num);
}

//const修饰指针变量或者指针变量的类型
void test3()
{
    int n = 100;

    int *p = &n;

    printf("*p = %d\n", *p);

    
  	//修改*p里面所保存的值
    n = 200;//通过值来修改
    printf("*p = %d\n", *p);
	
    //const修饰指针变量的类型,无法通过指针变量修改地址里面的内容
    //如果const int *p = &n;这里会报错
    *p = 300;//通过*p自己来修改
    printf("*p = %d\n", *p);

    //const修饰指针变量,无法修改指针变量保存的地址
    //int * const p = &n;
    int m = 400;//让p重新再保存一块地址
    p = &m;
    printf("*p = %d\n", *p);

}

int main()
{
    test3();

    return 0;
}

9.2 C++中的const

C++中const修饰全局变量或者指针变量以及指针变量的类型跟C语言是一样的,唯独修饰局部变量时与C语言有区别

  1. 当局部变量用一个常量初始化时,如果用const修饰,会将其保存在符号常量表
  2. 如果用volatile修饰,说明这个变量是易变的,不会保存在符号常量表中
  3. const修饰的变量如果同另一个变量初始化,则不会将其保存在符号常量表中

图片.png

#include <iostream>

using namespace std;

void test1()
{
    //当局部变量用一个常量初始化的时候,如果用const修饰,会将其保存在符号常量表中
    const int a = 100;

    //如果用volatile修饰,说明这个变量是易变的,不会保存在符号常量表中
    //volatile const int a = 100;
    cout << "a = " << a << endl;

    //a = 200;//不能通过自己本身修改
    //cout << "a = " << a << endl;

    //注意:C++对于类型优严格要求,类型必须一致否则报错
    int *p = (int *)&a;
    *p = 300;
    cout << "a = " << a << endl;
    cout << "*p = " << *p << endl;
    cout << "&a = " << &a << endl;
    cout << "p = " << p << endl;
}

void test2()
{
    int a = 100;
    //const修饰的变量如果同另一个变量初始化,则不会将其保存在符号常量表中
    const int b = a;
    cout << "b = " << b << endl;

    int *p = (int *)&b;
    *p = 333;
    cout << "b = " << b << endl;
}

struct Msg{
    int a;
    int b;
    char c;
};

void test3()
{
    const Msg g = {100, 200, 'w'};
    cout << g.a << ", ";
    cout << g.b << ", ";
    cout << g.c << endl;

    //没有保存再符号常量表
    Msg *p = (Msg *)&g;
    p->a = 666;
    p->b = 888;
    p->c = 'p';
    cout << g.a << ", ";
    cout << g.b << ", ";
    cout << g.c << endl;
}

int main()
{
    test3();

    return 0;
}

9.3 const和#define区别总结:

  1. const有类型,可进行编译器类型安全检查。#define无类型,不可进行类型检查.
  2. const有作用域,而#define不重视作用域,默认定义处到文件结尾.如果定义在指定作用域下有效的常量,那么#define就不能用。

十、inline内联函数

内联函数就是用inline修饰一个函数,将这个函数称之为内联函数

在类中定义的成员函数全部默认为内联函数

内联函数类似宏函数,使用效率比起普通函数要高,在c++中,预定义宏的概念是用内联函数来实现的,而内联函数本身也是一个真正的函数。内联函数具有普通函数的所有行为。唯一不同之处在于内联函数会在适当的地方像预定义宏一样展开,所以不需要函数调用的开销。因此应该不使用宏,使用内联函数。

在普通函数(非成员函数)函数前面加上inline关键字使之成为内联函数。但是必须注意必须函数体和声明结合在一起,否则编译器将它作为普通函数来对待。

#include <iostream>

using namespace std;

#define MYADD(x, y) x+y
#define MYADD1(x, y) (x+y)
#define MYMAX(a, b) (((a) > (b)) ? (a) : (b))

void test1()
{
    int sum = MYADD(100, 200);
    cout << sum << endl;

    //宏函数本质函数宏定义,所以在预处理阶段就是直接替换,所以不会自动将结果看做一个整体
    //MYADD(10, 5) * 100 --> 10 + 5 * 100
    int num = MYADD(10, 5) * 100;
    cout << num << endl;

    num = MYADD1(10, 5) * 100;
    cout << num << endl;

    int max = MYMAX(100, 20);
    cout << "max = " << max << endl;

    int a = 10, b = 5;
    //使用宏函数有时会有歧义
    //MYMAX(++a, b);
    // -->
    // ++a > b ? ++a : b;
    max = MYMAX(++a, b);
    cout << "max = " << max;
}

//使用inline修饰的函数称之为内联函数
//一般只能将简短的函数作为内联函数,如果函数内容过多即使加了inline也是普通函数
//如果简短的函数没有加inline并且会经常调用,编译器会将这个函数自动当做内联函数来使用
inline int MyMax(int a, int b)
{
    return a > b ? a : b;
}

void test2()
{
    int a = 10, b = 5;
    int max = MyMax(++a, b);
    cout << "max = " << max;
}

int main()
{
    test2();

    return 0;
}

十 一、函数的默认参数(缺省参数)

C++里面函数的形式参数可以设置默认值,在调用的时候如果不给对应位置的形参赋值,就会自动赋值为默认值,但是设置默认值的时候必须从右向左连续赋值

#include <iostream>

using namespace std;

void Dc21071StuMsg(string strclass, int id, string name, char sex = 'M', int score = 0)
{
    cout << strclass << ", ";
    cout << id << ", ";
    cout << name << ", ";
    cout << sex << ", ";
    cout << score << endl;
}
void test1()
{
    Dc21071StuMsg("dc21071", 1001, "张三", 'M', 90);
    Dc21071StuMsg("dc21071", 1002, "李四", 'W', 80);
    Dc21071StuMsg("dc21071", 1003, "王五");
}

int main()
{
    test1();

    return 0;
}