常见编程语言入门:c++

326 阅读4分钟

本文会对c++的基本使用做一下介绍。
由于c++是c语言的超集,这里假定各位(其实除了我也没几个人看)已经在c语言入了门且有typescript的基础,如果没入的,门在这里
本文主要参考C++ Primer 中文版(第 5 版)C++ Primer Plus(第六版),其中后者适合入门,前者偏综合。


概述

c++和c的关系就类似于ts和js,但ts仍然需要编译成js才能在宿主环境中运行,而c++已经不需要以c作为中间代码,直接编译、链接为目标程序,但c++的语法仍基本兼容c的语法,基本用法也类似,因此后面只会对有必要的地方

c++在c的基础上进行了进一步的抽象和封装,主要是面向对象和基于模板的泛型,这两种在ts中有类似的实现。

基本用法

大致和c一致,这里只讨论几个可能需要注意的点。

布尔类型

布尔类型在c++中用bool表示

引用

引用变量可以用来表示一个变量的别名,且必须在创建时被初始化,可以在函数中作为参数或返回值

 // 声明简单的变量
 int    i;
 double d;

 // 声明引用变量
 int&    r = i;
 double& s = d;

命名空间

c++为了解决全局作用域变量和函数的冲突问题,引入了命名空间,使用 namespace关键字

namespace namespace_name {
   // 代码声明
}

为了调用特定命名空间的变量和函数,可以

namespace_name::code;  // code 可以是变量或函数

也可以使用using namespace 指令后,在当前作用域直接使用该命名空间的内容

using namespace namespace_name;

内存管理

c++的存储类别和c大致相似,在手动内存分配方面,c++使用new和delete的方式。
可以使用new为任意类型的数据分配内存,语法为new data-type;,一个未分配值的指针可以使用null初始化

double* pvalue  = NULL; // 初始化为 null 的指针
pvalue  = new double;   // 为变量请求内存

内存使用完进行释放

delete pvalue;        // 释放 pvalue 所指向的内存

对于数组的内存分配方式为

char* pvalue  = NULL;   // 初始化为 null 的指针
pvalue  = new char[20]; // 为变量请求内存
delete [] pvalue;        // 删除 pvalue 所指向的数组

字符串

除了可以使用char数组表示,还可以使用string类

#include <string>
string str1 = "test";

输入输出

c++提供了面向对象的输入输出方式,在iostream中提供了 cin、cout用于输入和输出

#include <iostream>
 
using namespace std;
 
int main( )
{
   char name[50];
 
   cout << "请输入您的名称: ";
   cin >> name;
   cout << "您的名称是: " << name << endl;
 
}

函数

c++中的函数讨论以下

参数默认值

和js一样

int sum(int a, int b=20)
{
  return a + b;
}
 

函数参数

c++在c的按值传递和按指针传递之外还提供了按引用传递,其中后两种会改变实际参数,比如swap函数 按值传递并没用

void swap(int x, int y)
{
   int temp;
   temp = x; /* 保存 x 的值 */
   x = y;    /* 把 y 赋值给 x */
   y = temp; /* 把 x 赋值给 y */
   return;
}

按指针

void swap(int *x, int *y)
{
   int temp;
   temp = *x;    /* 保存地址 x 的值 */
   *x = *y;        /* 把 y 赋值给 x */
   *y = temp;    /* 把 x 赋值给 y */
  
   return;
}

按引用

void swap(int &x, int &y)
{
   int temp;
   temp = x; /* 保存地址 x 的值 */
   x = y;    /* 把 y 赋值给 x */
   y = temp; /* 把 x 赋值给 y  */
  
   return;
}

内联函数

默认的非内联函数会在调用时跳到指定内存执行,然后返回,而内联函数会将代码拷贝到需要调用函数的地方,用空间换时间。
适合简单的函数,在函数前面用inline关键字,类中的函数默认为内联。

class

c++利用class定义一个数据类型的蓝图,可以用来实例化一个对象,或者称为一个自定义的数据结构。
一个class结构如下

class classname{
 access specifiers://访问修饰符:private/public/proteced
   members variables;//变量
   members function(){};//方法
    
};

类中可以定义包含的数据和操作方法,对应成员分为实例成员(默认)和静态成员(添加static关键字)

类成员函数

class中方法可以在class中直接定义

class Box
{
   public:
      double length;      // 长度
      double breadth;     // 宽度
      double height;      // 高度
   
      double getVolume(void)
      {
         return length * breadth * height;
      }
};

也可以在外使用范围解析运算符(::)定义对应函数,此时class中只需要包含函数声明。

double Box::getVolume(void)
{
    return length * breadth * height;
}

创建对应类型对象

Box myBox;          // 创建一个对象
myBox.getVolume();  // 调用该对象的成员函数

构造函数和析构函数

这两种是特殊的成员函数,和classname一样,前者会在对应对象初始化时调用,可以用来做一些初始化动作,比如添加初始值,后者定义是需要在函数前添加~符号,会在被创建的对象被删除时调用。

拷贝构造函数

拷贝构造函数用于复用同类型的对象,形式如

classname (const classname &obj) {
   // 构造函数的主体
}

会在将对象作为参数传入函数(包括构造函数)

//传入构造函数
Complex c2(c1);
Complex c2 = c1;
#include<iostream>
using namespace std;
class A{
public:
    A(){};
    A(A & a){
        cout<<"Copy constructor called"<<endl;
    }
};
void Func(A a){ }
int main(){
    A a;
    Func(a);
    return 0;
}

或从函数返回时调用,如果没有显式定义,则会有一个默认的。

友元

一个对象private和protected对象本来是不能被外界访问的,c++提供了友元函数或友元类可以对其访问,比如

#include <iostream>
 
using namespace std;
 
class Box
{
   double width;
public:
   friend void printWidth( Box box );
   void setWidth( double wid );
};
 
// 成员函数定义
void Box::setWidth( double wid )
{
    width = wid;
}
 
// 请注意:printWidth() 不是任何类的成员函数
void printWidth( Box box )
{
   /* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
   cout << "Width of box : " << box.width <<endl;
}
 
// 程序的主函数
int main( )
{
   Box box;
 
   // 使用成员函数设置宽度
   box.setWidth(10.0);
   
   // 使用友元函数输出宽度
   printWidth( box );
 
   return 0;
}

继承

子类可以对基类中的成员进行继承,可以同时对多个基类继承

class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};

继承方式决定继承基类的哪些成员,默认private,具体为以下,无论哪种基类的private属性都不能继承

  • public 通常使用的方式,基类的public和protected会以相同类型被继承
  • protect 基类的public和protected会以protected类型被继承
  • private

重载

可以对类中的运算符或函数根据不同签名进行重载,其中签名包括函数名和参数个数和对应类型

函数

class printData
{
   public:
      void print(int i) {
        cout << "整数为: " << i << endl;
      }
 
      void print(double  f) {
        cout << "浮点数为: " << f << endl;
      }
 
      void print(char c[]) {
        cout << "字符串为: " << c << endl;
      }
};
 

运算符

比如对加号,作为成员函数进行定义

  // 重载 + 运算符,用于把两个 Box 对象相加
  Box operator+(const Box& b)
  {
     Box box;
     box.length = this->length + b.length;
     box.breadth = this->breadth + b.breadth;
     box.height = this->height + b.height;
     return box;
  }

多态

多态就是具有继承关系的不同对象调用同一个方法,实际的行为看各自实现。
其中要注意虚函数的概念,如果一个基类型指针指向一个子类对象,这时候调用对应方法就会调用基类的实现,如果添加visual定义虚函数,就会调用对应子类的方法,在ts等语言自动实现了虚函数的功能,可参考这里

模板和泛型

模板是泛型编程的基础,泛型编程即是一种独立于特定类型的功能实现,c++提供了STL(Standard Template Library)对常见数据结构进行了封装,可以直接使用,比如vector、list或dequeue等。

我们也可以自己实现自己的模板和泛型

自定义

模板包括函数模板和class模板。
函数模板形式如下,其中type是类型占位符

template <typename type> ret-type func-name(parameter list)
{
   // 函数的主体
}

比如


#include <iostream>
 
using namespace std;

template <typename T>
void Swap(T& a, T& b)
{
    T tmp = a;
    a = b;
    b = tmp;
}

void main()
{
    int a = 10;
    int b = 20;
    Swap(a, b);	//自动推到调用
    //Swap<int>(a, b);//显示指定调用
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
 
    float c = 12.3;
    float d = 23.4;
 
    //Swap(c, d); //自动推到调用
    Swap<float>(c, d); //显示指定调用
    cout << "c = " << c << endl;
    cout << "d = " << d << endl;
    system("pause");

}

class模板形式为

template <class type> class class-name {
}

#include<iostream.h>
template<typename T>    //模板声明,其中T为类型参数
class Compare{
  public:
    Compare(T i,T j)
    {
      x = i;
      y = j;
    }
    T max()
     {
      return (x>y)?x:y;
     } 
 private:
    T x,y; 
};
int main()
{
Compare<int>com1(3,7);                       //用类模板定义对象com1,此时T被int替代 
Compare<double>com2(12.34,56.78);            //用类模板定义对象com2,此时T被double替代 
Compare<char>com3('a','x');                  //用类模板定义对象com3,此时T被char替代 
cout<<"其中的最大值是:"<<com1.max()<<endl;   
cout<<"其中的最大值是:"<<com2.max()<<endl;
cout<<"其中的最大值是:"<<com3.max()<<endl;
return  0;


完结