day31-c++介绍

day31-c++介绍

一、c++简介

C++是一种编程语言,它是在C语言的基础上发展而来的,增加了面向对象、泛型和异常处理等特性。C++是一种多范式的语言,它支持面向过程、面向对象、泛型和函数式等编程范式。C++也是一种编译型的语言,它需要通过编译器将源代码转换为可执行的机器码。

C++的特点有以下几点:

  • C++是一种高效的语言,它提供了底层的访问能力,可以直接操作内存和硬件,也可以利用现代的优化技术提高性能。
  • C++是一种灵活的语言,它允许程序员根据不同的需求选择不同的编程风格和技术,也可以与其他语言进行混合编程。
  • C++是一种可移植的语言,它遵循了国际标准,可以在不同的平台和操作系统上运行,也可以利用标准模板库(STL)和第三方库扩展功能。

C++的适用场景有以下几点:

  • C++适合开发需要高性能、高可靠性、高安全性的系统软件和应用软件,例如操作系统、数据库、网络通信、图形图像、游戏等领域。
  • C++适合开发需要跨平台、跨语言的软件,例如嵌入式系统、物联网、云计算、人工智能等领域。
  • C++适合开发需要利用现有代码或库的软件,例如基于C语言或其他语言的遗留代码或开源代码等。

C++的学习路线有以下几点:

  • 入门阶段:学习C++的基本语法和面向对象编程思想,掌握类、对象、继承、多态等概念,熟悉常用的标准库和第三方库,完成一些简单的项目实践。
  • 进阶阶段:学习C++的高级特性和泛型编程思想,掌握模板、异常处理、智能指针等概念,深入理解STL的原理和实现,完成一些复杂的项目实践。
  • 提高阶段:学习C++的最新标准和新特性,掌握lambda表达式、移动语义、并发编程等概念,关注C++的发展趋势和前沿技术,完成一些创新的项目实践。



二、c++开发环境

  • Linux下的c++开发工具

    vim,gedit,vscode,g++

  • windows下的c++开发工具

    devcpp,vsxode+winGW

  • windows + linux

    用ssh在windows上远程连接Linux




三、c++基础知识

3.1 c++基本结构

C++是一种面向对象的编程语言,它由以下几个部分组成:

  • 预处理器指令:用于引入头文件,定义宏,设置条件编译等。
  • 全局变量和常量:用于在整个程序中存储和访问数据。
  • 函数:用于封装一组相关的语句,实现特定的功能。
  • 类:用于定义一种新的数据类型,包含数据成员和成员函数。
  • 对象:用于创建类的实例,调用成员函数,访问数据成员。
  • 继承:用于实现类之间的关系,使子类可以继承父类的特性和行为。
  • 多态:用于实现不同类型的对象可以使用相同的接口,根据对象的实际类型执行不同的操作。
  • 模板:用于实现泛型编程,使函数和类可以适用于不同类型的参数和数据。

C++基本结构的示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
cpp
// 预处理器指令
#include <iostream> // 引入输入输出流头文件
using namespace std; // 使用标准命名空间

// 全局变量和常量
const double PI = 3.14; // 定义一个常量
int count = 0; // 定义一个变量

// 函数
void printHello() // 定义一个无参无返回值的函数
{
cout << "Hello, world!" << endl; // 输出一行文字
count++; // 变量自增
}

// 类
class Circle // 定义一个圆类
{
private: // 私有部分
double radius; // 数据成员,半径
public: // 公有部分
Circle(double r) // 构造函数,初始化半径
{
radius = r;
}
double getArea() // 成员函数,计算面积
{
return PI * radius * radius;
}
};

// 主函数
int main()
{
printHello(); // 调用函数
Circle c(5); // 创建对象,传入半径为5
cout << "The area of the circle is " << c.getArea() << endl; // 输出圆的面积
cout << "The count is " << count << endl; // 输出变量的值
return 0; // 返回0表示程序正常结束
}

3.2 c++和c语法上的不同

  1. 隐式类型转换

在C中,可以隐式地将一个类型的变量赋值给另一个类型的变量,例如:

1
2
int x = 10;
double y = x; // 隐式地将int转换为double

这种隐式类型转换可能会导致精度损失或数据溢出,但是C编译器不会报错,只会给出一个警告。

而在C++中,这种隐式类型转换是不允许的,编译器会报错,提示类型不匹配。例如:

1
2
3
4

int x = 10;
double y = x; // 错误:不能将int转换为double

这是因为C++更加注重类型安全,要求程序员显式地进行类型转换,例如:

1
2
int x = 10;
double y = static_cast<double>(x); // 显式地将int转换为double

这样可以避免一些潜在的错误和风险。

  1. 函数重载

在C中,不能定义两个或多个同名但参数不同的函数,即使它们的返回值也不同。例如:

1
2
3
4
5
6
7
int add(int a, int b) {
return a + b;
}

double add(double a, double b) {
return a + b;
} // 错误:重复定义了函数add

这是因为C中的函数名是一个全局唯一的标识符,不能有重复。

而在C++中,可以定义两个或多个同名但参数不同的函数,这称为函数重载。例如:

1
2
3
4
5
6
7
int add(int a, int b) {
return a + b;
}

double add(double a, double b) {
return a + b;
} // 正确:重载了函数add

这是因为C++中的函数名是一个由函数名和参数列表组成的复合标识符,只要参数列表不同,就可以有相同的函数名。而且参数可以写默认值

1
2
3
4
void printfln(const a = "hello", int b=4) {
cout<<a<<endl;
cout<<b<<endl;
}

函数重载可以提高代码的可读性和灵活性,可以根据不同的参数类型选择合适的函数实现。

但要注意参数类型不一致时,会发生转换,但如果有两个符合条件的函数(例如输入的参数是int和float,把float转为int可以调用函数1,把int转为float可以调用函数2),编译器就会发生错误

  1. 结构体变量声明

在C中,定义一个结构体类型后,要声明一个该类型的变量,需要在变量名前加上关键字struct。例如:

1
2
3
4
5
6
struct Point {
int x;
int y;
};

struct Point p; // 声明一个结构体变量p

而在C++中,定义一个结构体类型后,要声明一个该类型的变量,可以省略关键字struct。例如:

1
2
3
4
5
6
struct Point {
int x;
int y;
};

Point p; // 声明一个结构体变量p

这是因为C++中的结构体类型和类类型是一致的,都属于用户自定义类型,可以直接使用其名称作为变量类型。

省略关键字struct可以简化代码的书写和阅读。

3.3 c++作用域

C++作用域是指变量或函数在程序中的可见范围。C++有四种作用域,范围从大到小:全局作用域、命名空间作用域和类作用域、局部作用域。

  • 全局作用域
    全局作用域是指定义在函数外部的变量或函数,它们在程序的任何地方都可以访问。全局变量或函数的命名应该避免与其他库或模块的命名冲突,否则会导致链接错误或不可预期的行为。
  • 命名空间作用域
    命名空间作用域是指定义在命名空间内部的变量或函数,它们可以在同一个命名空间内或者使用命名空间限定符访问。命名空间是一种组织代码的方式,可以避免不同模块之间的命名冲突,也可以提高代码的可读性和可维护性。C++标准库中的所有内容都位于std命名空间中,使用时需要加上std::前缀,或者使用using声明引入。
  • 类作用域
    类作用域是指定义在类内部的变量或函数,它们可以在类内部或者使用类对象访问。类是一种封装数据和操作的抽象,可以实现面向对象编程的特性,如封装、继承和多态。类内部的变量称为数据成员,类内部的函数称为成员函数。数据成员和成员函数可以有不同的访问权限,如公有、私有和保护,这样可以控制类对象对它们的访问程度。
  • 局部作用域
    局部作用域是指定义在函数内部的变量或函数,它们只能在函数内部使用。局部变量或函数的生命周期只限于函数的执行期间,函数结束后,它们会被销毁。局部变量或函数可以隐藏同名的全局变量或函数,这样可以提高程序的模块化和封装性。

3.4 c++引用

C++中的引用是一种特殊的变量,它可以用来表示另一个变量的别名。引用的作用是可以让我们通过不同的名字访问同一个内存地址,从而实现对变量的间接操作。引用的声明方式是在变量类型后面加上一个&符号,然后给出引用的名字和初始化的变量。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(void){
int x = 10; // 声明一个整型变量x
int &y = x; // 声明一个整型引用y,指向x

int a = 1;
int b = 2;
change(a,b);//a,b的值能被转换,a=2,b=1
return 0;
}
void change(int &a,int &b){
int tmp=a;
a=b;
b=tmp;
}

引用有以下几个特点:

  • 引用必须在声明时初始化,不能像指针那样先声明后赋值。
  • 引用一旦初始化,就不能改变指向的对象,也就是说引用是常量指针。
  • 引用没有自己的内存空间,它只是指向另一个变量的别名,所以不能对引用取地址。
  • 引用可以作为函数的参数和返回值,从而实现传递和返回对象的效果。

引用的优点是可以简化代码的书写,避免使用指针带来的复杂性和风险。引用的缺点是可能造成代码的可读性和可维护性降低,因为不容易区分引用和原始变量。因此,在使用引用时,应该遵循以下原则:

  • 尽量使用const引用,以防止修改指向的对象。
  • 尽量避免使用多层引用,以防止产生混乱和错误。
  • 尽量避免使用引用的引用,以防止出现未定义的行为。

3.5 内联函数

c++中可以用宏函数提高效率,但安全性降低

1
2
3
4
5
6
7
8
9
10
11
//宏函数只会进行引用,不是真正的函数
#define max(a,b) ((a)>(b)?(a):(b))

int main(void){
int max1;
int a = 7;
int b = 4;
max1 = max(a++,b); //实际上是((a++)>(b)?(a++):(b));
cout<<max1<<endl;
cout<<a<<endl; //结果是max=8,a=9
}

c++中引入了inlien关键字(内联函数),用来实现类似于宏函数的效果
但内联函数通过空间换取的时间,相当于直接把内联函数的代码嵌如到主函数中。空间开销大,一般内联函数不能太复杂

1
2
3
4
5
6
7
8
9
10
11
12

inline int max(int a,int b){
return a>b?a:b;
}

int main(void){
int max1;
int a=7,b=4;
max1 = max(a++,b);
cout<<max1<<endl;
cout<<a<<endl; //结果是max=7,a=8
}

3.6 const关键字

  1. const修饰类的成员函数

当我们在类的成员函数后面加上const关键字时,表示这个函数是一个常成员函数,它不会修改对象的任何数据成员。这样可以保证对象的状态不被意外改变,也可以增加代码的可读性和可维护性。

常成员函数的特点有:

  • 常成员函数只能访问类的const成员变量和const成员函数,不能访问非const的成员。
  • 常成员函数不能修改类的任何数据成员,也不能调用非const的成员函数(因为这些操作都可能改变对象的状态)。
  • 常成员函数可以被非const对象和const对象调用,但非const成员函数只能被非const对象调用。
  • 常成员函数可以被重载,即可以存在同名的const和非const版本的成员函数,它们的区别在于是否有const修饰符。

常成员函数的语法格式为:

1
返回值类型 类名::函数名(参数列表) const;

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Student{
public:
Student(char * name, int age, float score );
void show(); //非const成员函数
char *getname() const; //const成员函数
int getage() const; //const成员函数
float getscore() const; //const成员函数
private:
char * m_name;
int m_age;
float m_score;
};

char * Student::getname() const{
return m_name;
}

int Student::getage() const{
return m_age;
}

float Student::getscore() const{
return m_score;
}
  1. const修饰类的成员变量

当我们在类的成员变量前面加上const关键字时,表示这个变量是一个常数据成员,它只能在初始化列表中赋值,不能在其他地方修改。这样可以保证对象的数据不被意外改变,也可以增加代码的安全性和效率。

常数据成员的特点有:

  • 常数据成员必须在初始化列表中赋值,不能在构造函数体或其他地方赋值。
  • 常数据成员只能被const成员函数访问,不能被非const的成员函数访问。
  • 常数据成员可以是静态或非静态的,静态常数据成员还必须在类外初始化。

常数据成员的语法格式为:

1
2
3
4
5
6
class 类名{
public:
类名(参数列表):常数据成员(初始值){...}
private:
const 数据类型 数据名;
};

例如:

1
2
3
4
5
6
7
8
9
class Circle{
public:
Circle(double r):radius(r),area(PI*r*r){}
double getRadius() const {return radius;}
double getArea() const {return area;}
private:
const double radius; //常数据成员
const double area; //常数据成员
};
  1. const修饰对象
    首先,我们需要明确一点,const修饰的是对象本身,而不是对象的类型。也就是说,const修饰的对象仍然属于原来的类型,只不过它的状态不能被改变。例如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class Point {
    public:
    Point(int x, int y) : x_(x), y_(y) {}
    void setX(int x) { x_ = x; }
    void setY(int y) { y_ = y; }
    int getX() const { return x_; }
    int getY() const { return y_; }
    private:
    int x_;
    int y_;
    };

    Point p1(1, 2); // p1是一个普通的Point对象
    const Point p2(3, 4); // p2是一个const Point对象

    p1.setX(10); // OK,可以修改p1的状态
    p2.setX(20); // 错误,不能修改p2的状态

    Point* pp1 = &p1; // OK,可以用普通指针指向普通对象
    Point* pp2 = &p2; // 错误,不能用普通指针指向const对象
    const Point* pp3 = &p1; // OK,可以用const指针指向普通对象
    const Point* pp4 = &p2; // OK,可以用const指针指向const对象

    pp1->setX(30); // OK,可以通过普通指针修改普通对象的状态
    pp2->setX(40); // 错误,不能通过普通指针修改const对象的状态
    pp3->setX(50); // 错误,不能通过const指针修改普通对象的状态
    pp4->setX(60); // 错误,不能通过const指针修改const对象的状态
    从上面的例子可以看出,当我们用const修饰一个自定义对象时,有以下几个效果:
  • 我们不能直接调用该对象的任何非const成员函数,因为这些函数可能会修改该对象的状态。
  • 我们不能用普通指针或引用来指向该对象,因为这样可能会通过指针或引用来修改该对象的状态。
  • 我们只能调用该对象的const成员函数,因为这些函数保证了不会修改该对象的状态。
  • 我们只能用const指针或引用来指向该对象,因为这样保证了不会通过指针或引用来修改该对象的状态。

3.6 static关键字

  1. static可以使类的成员变量和成员函数与类的对象无关,即不需要创建对象就可以访问。static修饰的成员变量和成员函数属于类本身,而不属于某个对象,因此它们只有一份,被所有对象共享。这样可以节省内存空间,也可以实现一些全局的功能。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    class MyClass {
    public:
    MyClass(int value) : m_value(value) {}
    static void printCount() {
    std::cout << "s_count = " << s_count << std::endl;
    }
    private:
    static int s_count; // 静态成员变量
    int m_value;
    };

    int MyClass::s_count = 0; // 静态成员变量初始化要在类外

    int main() {
    MyClass obj1(10);
    MyClass obj2(20);
    MyClass::printCount(); // 输出s_count = 0
    obj1.printCount(); // 输出s_count = 0
    obj2.printCount(); // 输出s_count = 0
    MyClass::s_count = 1; // 静态成员变量修改
    MyClass::printCount(); // 输出s_count = 1
    obj1.printCount(); // 输出s_count = 1
    obj2.printCount(); // 输出s_count = 1
    return 0;
    }

  2. static可以实现类的封装性,即隐藏类的实现细节。static修饰的成员变量和成员函数只能在类的内部或者友元函数中访问,不能在类的外部访问。这样可以保护类的数据和行为,防止被外部修改或者滥用。
  3. static可以实现类的多态性,即同一个函数名可以有不同的行为。static修饰的成员函数是静态绑定的,即在编译时就确定了调用哪个函数。static修饰的成员函数不能被子类重写,也不能使用虚函数表实现动态绑定。这样可以提高程序的执行效率,也可以避免一些运行时错误。

总之,static在自定义类中的作用是使类的成员变量和成员函数与对象无关、实现类的封装性和多态性。在使用static时,需要注意以下几点:

  • static修饰的成员变量需要在类外初始化,否则会报错。
  • static修饰的成员函数不能访问非静态的成员变量和成员函数,否则会报错。
  • static修饰的成员函数不能被声明为const或者volatile,否则会报错。
  • static修饰的成员函数不能使用this指针,因为this指针指向当前对象,而静态成员函数与对象无关。



四、c++编译

c和c++混合编译时,先分别编译成.o文件,在放在一起编译

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2020-2024 nakano-mahiro
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信