本文会对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;
完结