第一个C++程序

#include <iostream>
using namespace std; //编译指令 int main() {
cout << "Hello World!" << endl;
return 0;
}

头文件

在C语言的传统中,头文件使用扩展名.h

//C风格
#include <stdio.h>

老式的C++延续了这个传统

//老式C++
#include <iostream.h>

而新式的C++抛弃了这个传统,转而去掉了.h

//新式C++
#include <iostream>

C++将部分C头文件转换为C++头文件并重新命名:去掉.h并加上前缀c

#include <cstdio>

在代码中包含cstdio,C++程序中也可以出现scanf()printf()

对于纯粹的C++头文件(比如iostream)来说,去掉.h不只是形式上的变化,还可能包含了命名空间

风格 约定 示例 C C++ 命名空间
C .h结尾 stdio.h ×
老式C++ .h结尾 iostream.h × ×
新式C++ 没有扩展名 iostream ×
转换后的C 加上前缀c,没有扩展名 cmath ×

由于C使用扩展名.h来表示这是一个C头文件

如果C++头文件继续沿用这个拓展名,容易造成混淆

其中一种解决方案是另起一个扩展名,比如.hpp等。

但最后大家却一致同意不使用任何扩展名 可能是懒的选了

编译指令

如果你使用的头文件是iostream,而不是iostream.h

那么你应该使用下面的语句来使iostream中的定义可用

using namespace std;

这句话告诉编译器,使用std这个命名空间,这样可以更方便的使用cout

关于命名空间的详细内容,留在了文章末尾的拓展部分。对于刚刚开始转向C++的萌新来说,最简单的方法就是先记住要写这句话就完了。

cout

cout << "Hello World!" << endl;

什么是cout

cout是一个预定义的对象(还没有提对象的概念,暂且把它当成一个东西、一个物件)。cout知道如何在屏幕上显示字符串、数字、单个字符等。

cout << 56;
cout << ' ';
cout << 9.10;

这个<<又是什么?

<<是C位运算的左移操作符,用来操作位。

在C++有了新的用途——输出。箭头方向指明了信息流动的方向。

信息可以流向cout从屏幕上输出,也可以通过键盘输入流向某个变量

cin >> a;

箭头方向指向a,说明这个信息是流向了a

endl是一个控制符,相当于C里面的换行符\n

面向对象

C++融合了3种不同的编程方式

  • 面向过程

(Procedure Oriented Programming)

  • 面向对象

(Object Oriented Programming)

  • 泛型编程

(Generic Programming)

通过C语言的学习,相信你已经对面向过程有所了解。假如我们现在要用程序来模拟一次上课的场景,用面向过程的思维来设计的话就是:

  • if (时间 == 8:00) 上课
  • 老师讲课,学生听课
  • 进入循环
  • ……
  • if (时间 == 9:40) 下课

那如果我们要用面向对象的思维来模拟上课场景,该怎么做?

什么是对象

面向对象在台湾有另一种叫法——物件导向。所谓的对象其实就是我们常说的东西,对象可以是

  • 一个按钮
  • 一盏灯

一个对象由下面两样东西组成

  • 数据(Data)
  • 操作(Operations)


以一盏灯为例

  • Properties可以是灯丝,Status是灯是否开启、灯的颜色。
  • Operations可以是开关,这个操作会改变内部的Data

上面这副蛋图,蛋黄位置的DataOperations所包裹。想要碰到Data只能穿过Operaions

为什么要把Data包裹起来?举个栗子,电视机的外壳。这个外壳除了让产品更好看之外,更重要的是保护着电视内部的电气元件,通常外壳上都会贴一个警告标签

非专业人士请勿拆卸

显然厂家不希望用户拆开这个外壳,如果用户拆开了外壳,自己去拔插电视内部的线路,很有可能会损坏电视。

但这个外壳会影响我们的使用吗?当然不会,设计者留出了很多按钮开关来操作电视机,这些按钮开关就是我们说的Operations

在OOP的世界里,大致有两类程序员

  • 设计类的程序员(设计者)
  • 使用类的程序员(用户)

对于设计者来说,用户不能直接碰到内部数据。用户只能通过设计者给出的接口来访问内部数据。

对于用户来说,用户关心的是功能而不是原理。正如电视机的按钮,按下就可以启动,用户不需要了解其中的电子电路知识。设计者对用户屏蔽了具体实现细节。

把数据和数据的操作放在一起,形成有机联系,叫做封装。

所以,如果我们要用面向对象思维来模拟一个上课过程,我们要做的就是写对象

  • 一个老师对象
  • 若干个学生对象

这些对象的互动就是上课的过程。

从对象到类

  • class

a collection of things sharing a common attribute.

  • object

entity

object是实体,class是概念

小明是一个学生对象,他的名字是 小明,期末考成绩90

从小明身上抽象出学生的一些共有属性,可以得到下面的类

class Student{
int sid;
int score;
};

另外有一个学生对象小红,她也会有学生类里面的属性

所以,class定义了object该长什么样,而object里面有具体的属性。

OOP的五项原则

  1. Everything is an object.
  2. A program is a bunch of objects telling each other what to do by sending messages.
    程序是由一堆互相之间传递消息的对象组成的。与之对应的是,面向过程语言(例如C)设计出来的程序是由一堆函数组成的。
  3. Each object has its own memory made up of other objects.
    每一个对象有他自己的内存,这些对象里面还可以有对象。
  4. Every object has a type.
    每个对象有一个自己的类型。
  5. All objects of a particular type can receive the same messages.

一个特定类型的对象可以接受相同的信息。反过来也可以说,能接受相同消息的对象可以认为是一样的对象。

结构体和类

//这是一个C结构体的标签
struct Student{
int sid;
int score;
};

用C语言定义这样一个结构体要在前面加struct

//C风格的定义
struct Student zs;

用C++定义时可以省略struct关键字

//C++风格的定义
Student zs;

同样的事情在C语言中实现要用到typedef

typedef struct _Student{
int sid;
int score;
}Student;

C++的结构体标签中还可以定义函数,这在C语言是不被允许的行为

//C++ 包含了操作方法的结构体
struct Student{
int sid;
int score;
void haha( void ){
cout << "haha..." << endl;
}
};

结合前面提到的OOP原理
C++的结构体可以放操作方法,有数据又有操作方法,所以C++中的结构体也是一个类class

struct Student{
int sid;
int score;
// 操作方法
void haha( void ){
cout << "haha..." << endl;
}
};

上面的struct可以改写成下面的class

class Student{
public:
int sid;
int score;
void haha( void ){
cout << "haha..." << endl;
}
};

访问控制

public

如果声明类的某个成员为public,那么这个成员可以被类外面的语句、函数随便使用。以Student类为例,其全部成员声明为public,可以直接修改zs的数据

Student zs;
zs.sid = 007;

private

改写Student

class Student{
private:
int sid;
int score;
public:
void haha( void ){
cout << "haha..." << endl;
}
};

现在sidscore是这个类所私有的成员,此时不允许在外部用zs.sid = 007来修改内部数据,必须是类里面的成员才能修改它们。

class Student{
private:
int sid;
int score;
public:
void haha( void ){
cout << "haha..." << endl;
}
void get_sid( void ){ //修改sid的接口
cin >> sid;
}
};

如果省略了publicprivate关键字

  • struct默认全部成员公开
  • class默认全部成员私有

布尔值

在C99之前,C语言是没有表示真假的布尔值,统统用int

#define TRUE  1
#define FALSE 0
int flag = 5 > 3;

flag的值只有01两种情况

C语言把非0当作真,0当作假,在C++也是一样的

//测试用例
if (3) {
cout << 1 << endl;
} if (-2) {
cout << 2 << endl;
}
//屏幕输出
1
2

C++提供了bool型变量,bool只占用一个字节的空间,用truefalse这两个字面值常量来表示真假。

bool flag = true;
flag = false;

int类型的数据来给bool类型赋值时

  • 非0的认为是true
  • 0认为是false
bool flag = 123;
cout << flag << endl;
//屏幕输出
1

auto

C++是一门强类型的语言,声明变量的时候必须清楚地知道表达式的类型,然而要做到这一点并非容易。
auto关键字让编译器自己去推断类型。和int这些特定类型不同,auto定义的变量必须有初始化。

auto a = 3;
a /= 2;
cout << a << endl;
//屏幕输出
1

3来给a初始化,编译器推断aint

auto a = 3.0;
a /= 2;
cout << a << endl;
cout << sizeof(a) << endl;
//屏幕输出
1.5
8

3.0a初始化,编译器推断出adouble类型。

引用 Reference

引用是已经定义的变量的别名

int b = 1;
int &r = b;

声明引用变量时必须进行初始化定义引用时,引用一旦创建好之后引用来源不能改变。

引用示例

C函数的参数传递,要么是值传递,要么是指针传递。

//C版本的交换函数
void swaq( int *a, int *b ) {
int temp;
temp = *a;
*a = *b;
*b = temp;
}

C++的参数传递不仅仅是值,还可以是引用。所以可以把交换函数的参数改为引用。

void swaq(int& a, int& b) {
int temp;
temp = a;
a = b;
b = temp;
}

在C代码中。看到func(a)可以放心的肯定func()得到的是一个值的拷贝,a原本的值不会被修改。

而到了C++,参数传递还可以传引用,看到func(a)不能简单地下结论。

如果你不希望参数引用的变量被修改,应该使用const

void func(const int& a);

右值引用

使用下面的语句给一个右值创建引用

const int& r = 123;
int&& r = 123; //右值引用

简要了解即可

赋值

C++可以编译下面的代码

(a = 3) = 666;
//屏幕输出
666
  • 在C语言中,(a = 3)的值为33是一个常量,常量不能做左值
  • 在C++,(a = 3)a的引用,可以继续赋值。

基于范围的for循环

int a[5] = { 1,2,5,3,4 };
for (int i : a) {
cout << i << ' ';
}
//屏幕输出
1 2 5 3 4

依次打印出数组a的5个元素

加上&表示引用后,可以修改元素的值

for (int& i : a) {
i++;
} for (int i : a) {
cout << i;
}
//屏幕输出
2 3 6 4 5

动态内存分配

申请内存

malloc()接受一个数值,指明要申请几个字节

//C版本
int size = 10;
int* p;
p = (int*)malloc(sizeof(int) * size);

到了C++,程序员不用自己数数了,直接指明我要什么,程序自己计算要多少空间。

//C++版本
p = new int[size];

释放内存

//C版本
free(p);
//C++版本
delete[] p;

new了之后一定要记得delete,有借有还再借不难。

加上 [] 释放整个数组,而不是只释放p[0]

重载 Overload

函数重载

C++可以编译下面的代码

int add( int x, int y );
int add( int x, int y, int z );

有两个函数名相同但参数列表不同的函数,在编译时编译器就会选取符合参数列表的函数。

错误重载1:相同的原型

但下面的代码不能通过编译

int add( int x, int y );
int add( int y, int z );

虽然参数的名字不相同,但两者的原型是一样的,都是

int add( int, int );

无法重载。

错误重载2:重载返回类型

下面的代码也不能通过编译

int add( int x, int y );
void add( int x, int y );

仅仅是返回类型不一样,编译器无法判断究竟重载哪个函数。
无法重载。

错误重载3:有歧义的重载

int add(int x, int y) {
return x + y;
} double add(double x, double y) {
return x + y;
} int main(void) {
cout << add(1, 2.5) << endl;
return 0;
}

main函数里调用add的语句有歧义。1可以转换为double,2.5也可以转换为int,编译器不知道该重载哪个。

操作符重载

现在有一个向量Vector

struct Vector {
int x;
int y;
};

向量的加法

(

x

1

,

y

1

)

+

(

x

2

,

y

2

)

=

(

x

1

+

x

2

,

y

1

+

y

2

)

(x_1,y_1)+(x_2,y_2) = (x_1+x_2,y_1+y_2)

(x1​,y1​)+(x2​,y2​)=(x1​+x2​,y1​+y2​)
+号只能对整数浮点数求值,通过重载运算符+,用+就可以实现向量加法

Vector operator +(const Vector& a, const Vector& b) {
Vector c;
c.x = a.x + b.x;
c.y = a.y + b.y;
return c;
}
int main() {
Vector a, b;
a.x = 3;
a.y = 4;
b.x = 1;
b.y = 5;
Vector sum;
sum = a + b;
cout << sum.x << " " << sum.y << endl;
return 0;
}

lambda表达式

auto f = []( int a, int b )-> int{ return a + b; };

这是函数的一种写法

  • f是一个函数指针
  • ( int a, int b )是参数列表
  • {}前面写函数的返回类型
  • {}里面写函数的内容。

扩展

命名空间可以帮助我们避免不经意的名字定义冲突,以及使用库中相同名字导致的冲突。标准库定义的所有名字都在命名空间std中。
通过命名空间使用标准库,当使用标准库中的一个名字时,必须使用::显式说明。

std::cout << "Hello World!" << std::endl;

要使用命名空间,头文件iostream不能有.h
using编译指令使得std命名空间里的所有名称都可用

之后都不需要使用std::

从C过渡到C++需要了解的“新特性”的更多相关文章

  1. Css3新特性应用之过渡与动画

    目录 背景与边框第一部分 背景与边框第二部分 形状 视觉效果 字体排印 用户体验 结构与布局 过渡与动画 源码下载 一.缓动效果 学习和利用贝塞尔曲线,默认支持ease,ease-in,ease-ou ...

  2. CSS3 新特性(box-sizing盒模型,背景线性渐变,filter滤镜,calc函数,transition过渡)

    1.盒子模型(box-sizing) CSS3 中可以通过 box-sizing 来指定盒模型,有两个值:即可指定为 content-box.border-box,这样我们计算盒子大小的方式就发生了改 ...

  3. CSS3新特性—过渡、转换

    过渡 转换 2D转换 2D转换包括四个方面:位移,缩放,旋转,倾斜 位移[让元素移动位置] transform: translate(100px,100px); 备注: 1. 如果只设置一个值,那么代 ...

  4. ios项目里扒出来的json文件

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px Menlo; color: #000000 } p.p2 { margin: 0.0px 0. ...

  5. Github上关于iOS的各种开源项目集合(强烈建议大家收藏,查看,总有一款你需要)

    下拉刷新 EGOTableViewPullRefresh - 最早的下拉刷新控件. SVPullToRefresh - 下拉刷新控件. MJRefresh - 仅需一行代码就可以为UITableVie ...

  6. iOS及Mac开源项目和学习资料【超级全面】

    UI 下拉刷新 EGOTableViewPullRefresh – 最早的下拉刷新控件. SVPullToRefresh – 下拉刷新控件. MJRefresh – 仅需一行代码就可以为UITable ...

  7. iOS:iOS开发非常全的三方库、插件等等

    iOS开发非常全的三方库.插件等等 github排名:https://github.com/trending, github搜索:https://github.com/search. 此文章转自git ...

  8. iOS开发--iOS及Mac开源项目和学习资料

    文/零距离仰望星空(简书作者)原文链接:http://www.jianshu.com/p/f6cdbc8192ba著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 原文出处:codecl ...

  9. iOS、mac开源项目及库汇总

    原文地址:http://blog.csdn.net/qq_26359763/article/details/51076499    iOS每日一记------------之 中级完美大整理 iOS.m ...

随机推荐

  1. SQL查询数据库名、表名、列名

    1.获取所有用户名SELECT name FROM Sysusers where status='2' and islogin='1'islogin='1'表示帐户islogin='0'表示角色sta ...

  2. Mybatis原理和代码剖析

    参考资料(官方) Mybatis官方文档: https://mybatis.org/mybatis-3/ Mybatis-Parent : https://github.com/mybatis/par ...

  3. JavaWeb中表单数据的获取及乱码问题

    首先使用一个用户提交界面作为举例(文本框,密码框,选择,下拉表单等),效果如下 注:HTML < form> 标签的 action 属性,其定义和用法是: 属性值为URL,表示向何处发送表 ...

  4. 关于IDEA无法加载main方法的bug

    问题现象 main方法没有run按钮 问题解决 发现args显示灰色未调用,原来是之前莫名其妙调用了sun包下的String 删除调用问题解决!

  5. AtomicStampedReference AtomicReference解决CAS机制中ABA问题

    AtomicStampedReference AtomicReference解决CAS机制中ABA问题 AtomicStampedReference AtomicStampedReference它内部 ...

  6. 为什么Class实例可以不是全局唯一的——自定义类加载器

    为什么Class实例可以不是全局唯一的 通过定义两个类加载器加载同一字节码文件来证明Class实例为什么不是全局唯一的 1.将一个名为Demo(没有后缀)的字节码文件放在D盘根目录 2.定义两个类加载 ...

  7. 如何在MacBook M1上无缝切换Win11和MacOS?

    2020年,MacBook M1发布后,由于其夸张到离谱的性能表现,苹果又一次在知名度和销量上真正实现了双丰收. 抛开M1和MacOS其他的华丽特色不谈,很多习惯了Windows系统的同学,在换了这台 ...

  8. K8S命令行工具——kubectl

    1.kubectl概述 2.kubectl命令的语法 例子: 3.kubectl子命令使用分类 (1)基础命令 (2)部署和集群管理命令 (3)故障和调试命令 (4)其他命令 4.kubectl命令例 ...

  9. python库--pandas--MultiIndex

    *表示后面会重复用到此参数 创建层次化索引 pd.MultiIndex 构造器 MI levels 每个级别不重复的标签 labels 每个级别的整数指定每个位置 *sortorder=None   ...

  10. 三剑客之sed编辑器 基操

    目录: 一.sed编辑器 二.打印内容 三.使用地址 四.删除行 五.替换 六.插入 一.sed编辑器 sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流. sed ...