C++ 语言介绍
介绍
C++是一种被广泛使用的计算机程序设计语言。它是一种通用程序设计语言,支持多重编程范式,例如过程化程序设计、数据抽象、面向对象程序设计、泛型程序设计和设计模式等。
比雅尼·斯特劳斯特鲁普博士在贝尔实验室工作期间在20世纪80年代发明并实现了C++。
安装
brew install cpp
基础知识
- C 语言标准头文件
math.h
、stdio.h
在 C++ 中命名为 cmath
、cstdio
#include <cmath>
#include <cstdio>
int main()
{
double a = 9.9;
a = sqrt(a);
printf("%lf\n", a);
return 0;
}
typedef
#include <iostream>
using namespace std;
typedef int INT;
int main() {
INT i = 1;
cout << i << endl;
return 0;
}
注释
多行注释
/*
xxxx
*/
单行注释
// xxx
字符串 string
本质为:
typedef std::basic_string<char> string;
#include <iostream>
#include <string>
using namespace std;
typedef string String;
int main() {
// 默认构造函数,没有参数
string s1;
// 赋值运算
s1 = "hello";
cout << s1 << endl;
// 拷贝构造函数,等价于 string s2 = "hello";
string s2("hello");
cout << s2 << endl;
// 拷贝构造函数
String s3("world!");
cout << s3 << endl;
// args: (C string, number of chars)
string s4("this is a C string", 10); // output is "this is a "
cout << "s4 is " << s4 << endl;
// args: (C++ string, start position, number of characters)
string s5(s4, 3, 3);
cout << "s5 is " << s5 << endl;
// args: (number of characters, char)
string s6(6, '#');
cout << "s6 is " << s6 << endl;
// args: (start, end)
string s7(s4.begin(), s4.end()-3);
cout << "s7 is " << s7 << endl;
string s8 = s7 + s6;
cout << "s8 is " << s8 << endl;
for(int i=0; i!=s8.size(); i++) {
cout << i << " " << s8[i] << " ";
}
cout << endl;
// 常量迭代器const_iterator;变量迭代器 iterator
string::const_iterator ii;
int i = 0;
for(ii=s8.begin(); ii!=s8.end(); ii++) {
cout << i++ << " " << *ii << endl;
}
return 0;
}
向量 vector
#include <iostream>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
int main() {
// vector 本质为模板函数
vector<double> x;
x.resize(3);
for (vector<double>::size_type i=0; i<3; i++) {
cin >> x[i++];
}
for (vector<double>::iterator it=x.begin(); it!=x.end(); it++) {
cout << *it << endl;
}
return 0;
}
命名空间
- 命名空间
namespace
- 作用:防止名字同名冲突
- 使用运算符
::
限定某个名字属于哪个命名空间 namespace
- 常见的3种方法使用名称空间N的param
using namespace N; // 引入整个命名空间
using N::param; // 引入单个
N::param; // 程序中通过命名空间前缀引用
#include <cstdio>
namespace F
{
int x;
void f(){
printf("f...");
}
int g() {
printf("%d\n", x);
return x;
}
}
namespace G
{
double x;
double g() {
printf("%lf\n", x);
return x;
}
}
int main()
{
F::x = 1;
F::g();
G::x = 3.14;
G::g();
return 0;
}
iostream
- C++的输入输出流库(头文件
iostream
)
- 标准名字空间
std
,包括标准输入输出库
cout
代表表输出流(窗口)
cin
代表标准输入流(键盘)
引用类型
- 引用经常用作函数的形参,形参和实参指向同一个对象,修改同时生效
- 适用于实参内存大时,用引用代替传值提高内存利用率
- 若函数中不希望修改到实参,可以使用 const 符,如
void swap(int &a, coust int &b)
#include <iostream>
using namespace std;
void swap(int *a, int *b)
{
cout << "before swap a is " << a << ", b is " << b << endl;
int t = *a;
*a = *b;
*b = t;
cout << "before swap a is " << a << ", b is " << b << endl;
}
int main()
{
double a = 9.9;
double &b = a; // 相当于 b 是 a 的别名
b = 3.14;
cout << "a is " << a << endl;
int x = 1, y = 2;
swap(&x, &y);
cout << "swap x is " << x << ", y is " << y << endl;
return 0;
}
异常
#include <iostream>
using namespace std;
int main()
{
int a;
cout << "Input a: ";
cin >> a;
cout << endl;
try {
if (a > 100) throw 100;
if (a < 60) throw "666";
throw "ok";
}
catch (int result) {
cout << "v is " << a << endl;
}
catch (char * s) {
cout << "s is " << string(s) << endl;
}
catch (...) { // 捕获其他情况
cout << "ok" << endl;
}
return 0;
}
- 默认参数:函数的形参可以有默认值,但必须放到最右边
#include <iostream>
using namespace std;
int add(int a, int b=60) {
return a + b;
}
int main() {
cout << add(1, 2) << endl;
cout << add(6) << endl;
return 0;
}
- 函数重载:C++ 支持函数同名、形参不同(参数个数或参数类型)
- 调用函数时,编译器将根据实参和形参选择最佳的函数
- 若存在多个难以区分的最佳函数,报错
- 不能根据返回值类型区分同名函数
#include <iostream>
using namespace std;
int add(int a, int b=60) {
return a + b;
}
double add(double a, double b=60) {
return a + b;
}
int main() {
cout << add(1, 2) << endl;
cout << add(3.14) << endl;
return 0;
}
模板函数
模板函数(template)
编译器自动生成针对指定数据类型的函数
#include <iostream>
using namespace std;
template<class T>
T maxFunc(T a, T b) {
// return a>b?a:b;
if(a > b) return a;
else return b;
}
template<class T1, class T2>
T1 minFunc(T1 a, T2 b) {
// return a<b?a:b;
if(a < b) return a;
else return (T1)b;
}
int main()
{
int a=3, b=4;
cout << "max of " << a << ", " << b << " is " << maxFunc(a, b) << endl;
double x=3.14, y=6.66;
cout << "max of " << x << ", " << y << " is " << maxFunc(x, y) << endl;
int c=5;
double z=8.88;
cout << "min int of " << c << ", " << z << " is " << minFunc(c, z) << endl;
return 0;
}
运算符重载
#include <iostream>
using namespace std;
struct Vector {
double x;
double y;
};
// 重载 + 运算
Vector operator + (Vector a, Vector b) {
Vector s;
s.x = a.x + b.x;
s.y = a.y + b.y;
return s;
}
// 重载输出 <<
ostream& operator << (ostream& o, Vector a) {
o << "(" << a.x << ", " << a.y << ")";
return o;
}
int main() {
Vector a, b;
a.x = 1;
a.y = 2;
b.x = 10;
b.y = 11;
Vector s = a + b;
cout << s.x << ", " << s.y << endl;
operator << (cout, s) << endl;
cout << s << endl << endl;
return 0;
}
inline
inline
声明内联函数,一般用于不包含循环的简单函数中,编译器通过内联展开,提高运行效率
#include <iostream>
using namespace std;
inline int add(int a, int b)
{
return a + b;
}
int main()
{
// 下面2行产生向的代码
cout << add(1, 2) << endl;
cout << 1 + 2 << endl;
return 0;
}
动态内存分配
- 关键字
new
和 delete
用来对类对象调用初始化(构造函数)和销毁(析构函数)
new
分配的是堆存储空间(所有程序拥有的共享内存空间)
- C 语音的malloc/alloc/realloc和free类似,C++是升级版本
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
// 申请一块存放double值的内存块
double pi = 3.14;
// 指针变量,保存double类型的地址变量;pp值的类型为double *
double *pp;
// 取地址运算符&用来获取 pi 变量的地址;pp 和 *pi 都是double *类型
pp = π
// 解引用运算符*用来获取指针变量指向的变量
*pp = 6.66;
cout << "*pp = " << *pp << " pi = " << pi << endl;
cout << "Input a number: ";
cin >> *pp; // 输入的变量pp指向double内存块的值
cout << "*pp = " << *pp << " pi = " << pi << endl;
// new 用来分配容量为 double 值的内存块,并返回改内存块的地址,类型为 double *;该地址被保存在pp中,pp指向新内存块,该内存块的值是未知的
// new 对 double 类型的元素调用 double 的构造函数做初始化
pp = new double;
// 初始化
*pp = 3.14;
cout << "Input a number: ";
cin >> *pp; // 输入的变量pp指向double内存块的值
cout << "*pp = " << *pp << endl;
// delete 释放动态分配的内存空间
delete pp;
// new 分配可以存放5个double值的内存空间,返回该连续内存空间的起始地址,且指针类型是double *(即第一个double元素的地址);new 是队每个double元素调用double类型的构造函数初始化
pp = new double[5];
pp[0] = 3.14;
pp[1] = pp[0] * 2;
cout << pp[0] << ", " << pp[1] << endl;
// delete 释放指向多个double类型的动态分配的内存空间;为每个double类型的元素调用double的析构函数释放内存;不指定 [] 时,仅释放第一个 double 的内存空间
delete[] pp;
int l = 5;
// new 分配指定(随机)大小的double类型元素
pp = new double[l];
for(int i=0; i<l; i++) {
// 通过指针访问元素
pp[i] = i;
cout << i << " " << pp[i] << endl;
}
double *p = pp;
for(int i=0; i<l; i++) {
cout << *(p+i) << " ";
}
cout << endl;
for (double *i=pp, *e=pp+l; i<e; i++) {
cout << *i << " ";
}
cout << endl;
// delete 可以防止内存泄露
delete[] pp;
return 0;
}
类 class
在 C 的 struct 类型上,添加成员函数,从而将一个概念或实体的所有属性组合在一起
struct 形式
#include <iostream>
using namespace std;
struct Date {
int y, m, d;
void init(int year, int month, int day) {
y = year;
m = month;
d = day;
}
void print() {
cout << y << "-" << m << "-" << d << endl;
}
Date& add(int day) {
d = d + day;
// this 指向调用该函数的类型对象指针;*this 是调用该函数的那个对象;返回 *this 就是返回自引用本身,可以实现链式调用
return *this;
}
Date& operator+=(int day){
d = d + day;
return *this;
}
};
int main() {
Date date;
date.print();
// init 方法,对 struct 初始化
date.init(1991, 8, 18);
date.print();
date.add(1).add(3);
date.print();
// += 运算符重载
date += 1;
date.print();
(date +=1) += 2;
date.print();
return 0;
}
构造函数和析构函数
- 构造函数是和类名同名且返回值为void的函数,在定义对象时会自动调用
- 构造函数用于初始化类对象成员,包括申请一些资源,如分配内存、打开文件等
- 析构函数在类对象被销毁时被自动调用,用来释放该对象占用的资源,如释放内存、关闭文件等
- 拷贝构造函数:定义一个类对象时,使用同类型的对象初始化新对象
- 赋值运算符:一个对象赋值给另外一个对象
#include <iostream>
using namespace std;
struct Date {
int y, m, d;
// 默认构造函数
Date(){
cout << "default constructor invoke!" << endl;
}
// 带参构造函数
Date(int month, int day) {
m = month;
d = day;
cout << "constructor invoke!" << endl;
}
// 带参构造函数
Date(int year, int month, int day=1) {
y = year;
m = month;
d = day;
cout << "constructor invoke!" << endl;
}
void print() {
cout << y << "-" << m << "-" << d << endl;
}
};
int main() {
Date date1;
date1.print();
Date date2(1991, 8, 18);
date2.print();
return 0;
}
class
- class 定义的类的成员默认都是
私有的(private)
,外部函数无法通过类对象.成员或函数
调用
private
定义私有的成员或函数,不对外暴露,一般保存类的私有对象
public
定义公有的成员或函数,可以被类外调用
public
的公开成员(一般是函数)称为该类的接口,外部函数通过对象.成员或函数
访问
protected
#include <iostream>
#include <cstring>
using namespace std;
// struct people {
class people {
// private 定义私有的成员和函数
private:
char *name;
int age;
// public 定义公开的成员和函数
public:
people(){
cout << "default constructor invoke!" << endl;
}
// 构造函数,带默认值
people(char *n="no_name", int a=15) {
int l = strlen(n);
name = new char(l+1);
strcpy(name, n);
age = a;
cout << "constructor invoke!" << endl;
}
char *get_name() {
return name;
}
void set_name(char *n="no_name") {
int l = strlen(n);
name = new char(l+1);
strcpy(name, n);
}
int get_age() { return age; }
void set_age(int a) { age = a; }
void print() {
cout << "{name: " << name << ", age: " << age << "}" << endl;
}
// 声明类体外函数
void print2();
virtual ~people() {
delete[] name;
cout << "destructor invoke!" << endl;
}
};
// 类体外定义方法(成员函数),必须在类定义中声明,类体外要有类作用域
void people::print2() {
cout << "{name: " << name << ", age: " << age << "}" << endl;
}
int main() {
// people p1();
people p2("zhangsan", 18);
people p3("lisi", 19);
// p1.print();
p2.print();
p3.print();
p2.set_name("xyz");
cout << p2.get_name() << endl;
// 调用类体外函数
p2.print2();
return 0;
}
class 模板
类模板可以将一个类变成类模板
或模板类
,类似于模板函数
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
using namespace std;
template<class T>
class Array {
private:
int size;
T *data;
public:
Array(int s){
size = s ;
// data = new T[s];
data = new T[s];
}
T &operator [] (int i) {
if (i<0 || i >= size) {
cerr << endl << "Out of range" << endl;
exit(EXIT_FAILURE);
}
else return data[i];
}
virtual ~Array() {
delete[] data;
cout << "destructor invoke!" << endl;
}
};
int main() {
Array<int> arr(5);
arr[0] = 1;
arr[1] = arr[0] + 6;
cout << arr[1] << endl;
// arr[100] = 3; // err occur
Array<string> s(5);
s[0] = "hello";
s[1] = "world";
cout << s[1] << endl;
return 0;
}
继承和派生
继承(inheritance)
一个派生类(derived class)从一个或多个父类(parent class)/基类(base class)继承父类的属性和行为,也可以扩展自己的属性和行为
派生(derivator)
- 虚函数(virtual Functions)
- 派生类的指针可以自动转化为基类指针,用一个指向基类的指针分布指向基类对象和派生类对象
虚函数(pure virtual function)
和抽象类(abstract base class)
- 函数体
=0
的虚函数称为纯虚函数
- 包含纯虚函数的类称为
抽象类
#include <iostream>
#include <string>
using namespace std;
class Animal {
protected:
std::string name;
public:
Animal(std::string n) : name(n)
{}
virtual void speak();
// virtual const void speak() = 0;
};
// Animal::Animal(string n) :name(n) // 初始化成员属性
// {
// // 等价于 name = n;
// }
void Animal::speak() {
cout << name << endl;
}
// 继承多个父类,使用 , 分隔;即多重派生类(Multiple inheritance)
class Cow : public Animal
{
public:
int age;
public:
Cow(std::string n, int a=1) : Animal(n), age(a)
{}
void speak();
};
// 派生类的构造函数仅描述它自己属性和其直接基类的初始值,只能使用父类的构造函数初始化父类的属性
// Cow::Cow(string n, int a) :Animal(n), age(a) {
// }
void Cow::speak() {
cout << "age is " << age << endl;
Animal::speak();
}
int main() {
Cow x("zhangsi", 2);
x.speak();
Animal y("lisi");
y.speak();
Animal *p = &x;
p->speak();
Animal* pp[10];
int num = 0;
// Animal* as[100];
}
其他
ci