关于 C++ 基本概念介绍

2017-03-20 language c/cpp

一般会将 C++ 划分为所谓的中级语言,从底层的 C 语言发展而来,提供了比 C 更丰富的特性,而又没有提供类似 Java、Python 等语言的高级特性,所以,介于中间,称之为中级语言。

随着 C++11 标准的发布,以及更新的 C++0x 标准,C++ 提供的功能越来越完善。

这里仅简单介绍下基本的概念。

简介

C++ 是由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发的,进一步扩充和完善了 C 语言,是一种面向对象的程序设计语言,可以行于多种平台上,如 Windows、MAC、Unix、Linxu 等各种版本。

不过不像 Java、Python 这类语言,其运行依赖于底层的虚拟机进行解释,编译后的代码无需重新编译,而 C++ 在不同的平台上需要重新编译,以生成不同的二进制文件。

这里,主要以 Linux 平台上的 gcc 为例。

示例

如下是一个最简单的 Hello World 示例。

#include <iostream>

using namespace std;

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

通过 using namespace std 标示使用标准的命名空间,可以选择使用多个,只要不发生命名空间的冲突即可。在编译的时候这里使用最新的 C++11 标准,可以使用 g++ -std=c++11 -o hello hello.cpp 命令进行编译。

面向对象

在面向对象的编程 (OOP) 中包含了比较重要的三大特性:封装、继承和多态。

封装

使代码模块化,通过对象封装了其特性和行为,分别称之为成员变量以及成员函数。其中成员访问管理分成了三类:

  1. public 类、类对象、派生类、派生类对象 均可访问。
  2. protected 类、派生类可以访问;类对象、派生类对象不可以访问。
  3. private 只有类内部可以访问。

继承

扩展已经存在的代码,可以通过已有的数据类型定义新的类型,继承老成员,并定义新成员。

包括了公有 Public、保护 Protected、私有 Private 继承,共三种方式,主要是对其父类成员中的访问权限设置。

多态 Polymorphisn

C++ 支持编译时以及运行时的多态性,分别通过函数重载以及虚函数来实现,注意,运行时的多态是通过虚拟函数指针实现的,也就是为什么是运行时动态绑定。

可以查看如下的 double GetArea(Shape &s) 函数,其入参是基类 Shape ,允许用户传入其派生类对象,例如 RectangleCircle,也就是调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。

示例

如下是一个简单的示例,展示一些基础的特性,其中 class Shape 包含了纯虚函数,也就是一个接口类,无法进行实例化,而派生类包含了四边形、圆形的实现。

#include <iostream>

using namespace std;

// Abstract Base Class
class Shape {
protected:
private:
    // int pri{}; // init, equal to int pri=0

public:
    // Pure Virtual Function
    virtual double Area() = 0;
};

class Rectangle : public Shape {
//protected:
private:
    double width, height;

public:
    // Simple Constructor
    Rectangle(double w, double h) {
        width = w;
        height = h;
    }

    // Destructor
    ~Rectangle() = default; // equal to ~Rectangle() { } Do nothing

    double Area() override {
        return width * height;
    }
};

class Circle : public Shape {
private:
    static constexpr double PI = 3.1415926;
    double radius;

public:
    explicit Circle(double r) {
        radius = r;
    }

    double Area() override;

    [[nodiscard]] double GetDiameter() const;

    friend void DumpInfo(Circle &c);
};

void DumpInfo(Circle &c) {
    cout << "radius is " << c.radius << endl;
}

double Circle::Area() {
    return PI * radius * radius;
}

double Circle::GetDiameter() const {
    return radius * 2;
}

double GetArea(Shape &s) {
    return s.Area();
}

int main() {
    Rectangle rec(10, 100);
    Circle c(10);

    DumpInfo(c); // friend function

    cout << "Area Rect=" << GetArea(rec) << " Circle=" << GetArea(c) << "Diameter=" << c.GetDiameter() << endl;
}

类中函数的。

其它

初始化列表

对于简单的对象可以使用初始化列表,但是需要注意,初始化列表是按照声明的顺序,而非在初始化列表中的顺序。

#include <iostream>

class Rectangle {
public:
    double width, height;
    Rectangle(double w): height(w), width(height) {}
};

int main() {
    Rectangle r(1.2);
    std::cout << r.height << std::endl << r.width << std::endl;
}

上述的代码初始化时,实际上会先将 width 初始化为 height,而此时的 height 变量没有初始化,是个随机值,通常会很大;接着,才会通过入参 w 初始化 height 变量。所以,最终的结果导致 width 变量值随机,height 的值是入参。

另外,在初始化列表中可以使用 new 关键字,例如 Array(int s): size(s), data(new int[s])

多线程

C++11 提供了标准的线程库 std::thread ,可以不再显式依赖 pthread 提供的线程库,实际上底层仍然使用的是该库,这也就是为什么链接时需要添加 -lpthread 或者 -pthread 选项。

#include <thread>
#include <unistd.h>
#include <iostream>

using namespace std;

void hello(void)
{
        usleep(1000);
        cout << "Hello Concurrent World" << endl;
        cout << "Current thread ID " << this_thread::get_id() << endl;
}

int main(void)
{
        thread thd(hello);

        cout << "Hello World" << endl;
        thd.join();
        cout << "All threads joined!" << endl;

        return 0;
}

友元

可以是一个函数或者类,这样通过友元函数可以直接访问类中的 private 以及 protected 的成员,需要注意,友元不是类的成员,也就不能使用 this 指针。