第一个C++程序

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

头文件

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

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

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

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

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

  1. //新式C++
  2. #include <iostream>

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

  1. #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中的定义可用

  1. using namespace std;

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

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

cout

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

什么是cout

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

  1. cout << 56;
  2. cout << ' ';
  3. cout << 9.10;

这个<<又是什么?

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

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

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

  1. 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

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

  1. class Student{
  2. int sid;
  3. int score;
  4. };

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

所以,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.

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

结构体和类

  1. //这是一个C结构体的标签
  2. struct Student{
  3. int sid;
  4. int score;
  5. };

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

  1. //C风格的定义
  2. struct Student zs;

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

  1. //C++风格的定义
  2. Student zs;

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

  1. typedef struct _Student{
  2. int sid;
  3. int score;
  4. }Student;

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

  1. //C++ 包含了操作方法的结构体
  2. struct Student{
  3. int sid;
  4. int score;
  5. void haha( void ){
  6. cout << "haha..." << endl;
  7. }
  8. };

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

  1. struct Student{
  2. int sid;
  3. int score;
  4. // 操作方法
  5. void haha( void ){
  6. cout << "haha..." << endl;
  7. }
  8. };

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

  1. class Student{
  2. public:
  3. int sid;
  4. int score;
  5. void haha( void ){
  6. cout << "haha..." << endl;
  7. }
  8. };

访问控制

public

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

  1. Student zs;
  2. zs.sid = 007;

private

改写Student

  1. class Student{
  2. private:
  3. int sid;
  4. int score;
  5. public:
  6. void haha( void ){
  7. cout << "haha..." << endl;
  8. }
  9. };

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

  1. class Student{
  2. private:
  3. int sid;
  4. int score;
  5. public:
  6. void haha( void ){
  7. cout << "haha..." << endl;
  8. }
  9. void get_sid( void ){ //修改sid的接口
  10. cin >> sid;
  11. }
  12. };

如果省略了publicprivate关键字

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

布尔值

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

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

flag的值只有01两种情况

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

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

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

  1. bool flag = true;
  2. flag = false;

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

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

auto

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

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

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

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

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

引用 Reference

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

  1. int b = 1;
  2. int &r = b;

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

引用示例

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

  1. //C版本的交换函数
  2. void swaq( int *a, int *b ) {
  3. int temp;
  4. temp = *a;
  5. *a = *b;
  6. *b = temp;
  7. }

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

  1. void swaq(int& a, int& b) {
  2. int temp;
  3. temp = a;
  4. a = b;
  5. b = temp;
  6. }

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

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

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

  1. void func(const int& a);

右值引用

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

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

简要了解即可

赋值

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

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

基于范围的for循环

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

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

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

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

动态内存分配

申请内存

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

  1. //C版本
  2. int size = 10;
  3. int* p;
  4. p = (int*)malloc(sizeof(int) * size);

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

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

释放内存

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

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

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

重载 Overload

函数重载

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

  1. int add( int x, int y );
  2. int add( int x, int y, int z );

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

错误重载1:相同的原型

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

  1. int add( int x, int y );
  2. int add( int y, int z );

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

  1. int add( int, int );

无法重载。

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

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

  1. int add( int x, int y );
  2. void add( int x, int y );

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

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

  1. int add(int x, int y) {
  2. return x + y;
  3. }
  4. double add(double x, double y) {
  5. return x + y;
  6. }
  7. int main(void) {
  8. cout << add(1, 2.5) << endl;
  9. return 0;
  10. }

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

操作符重载

现在有一个向量Vector

  1. struct Vector {
  2. int x;
  3. int y;
  4. };

向量的加法

(

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​)
+号只能对整数浮点数求值,通过重载运算符+,用+就可以实现向量加法

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

lambda表达式

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

这是函数的一种写法

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

扩展

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

  1. 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. win7上帝模式详解

    最近,Windows7"GodMode"(上帝模式)被国内各大网站和论坛炒得沸沸扬扬."GodMode"始见于国外网站"GeekInDisguise& ...

  2. C# .NetCore简单实现无限递归的功能

    1:在实际开发中,我们会经常使用到无限递归的情况,如菜单,父子级等的情况 2:Code 1 using System; 2 using System.Collections.Generic; 3 us ...

  3. Tolist案例(父子传参实现增删改)

    1.Tolist案例(父子传参实现增删改) 目录结构 实现效果: App.jsx class App extends Component { // 状态在哪里, 操作状态的方法就在哪里 state = ...

  4. golang 模板 html/template与text/template

    html模板生成: html/template包实现了数据驱动的模板,用于生成可对抗代码注入的安全HTML输出.它提供了和text/template包相同的接口,Go语言中输出HTML的场景都应使用t ...

  5. openresty lua-resty-string md5 sha aes random string

    安装 https://github.com/openresty/lua-resty-string $ sudo opm get openresty/lua-resty-string $ ls -al ...

  6. openresty(nginx) 配置 http与https使用同一个端口,禁止 IP 直接访问

    准备好工作目录 mkdir work cd work mkdir conf logs 准备好 conf/nginx.conf 配置文件, 把 your.domain 换成你自己的域名 user abc ...

  7. 1,Spark参数调优

    Spark调优 目录 Spark调优 一.代码规范 1.1 避免创建重复RDD 1.2 尽量复用同一个RDD 1.3 多次使用的RDD要持久化 1.4 使用高性能算子 1.5 好习惯 二.参数调优 资 ...

  8. Pytest 系列(24)- allure 环境准备

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html allure 和 pytest 相 ...

  9. Java优化if-else代码

    前言 开发系统一些状态,比如订单状态:数据库存储是数字或字母,但是需要显示中文或英文,一般用到if-else代码判断,但这种判断可读性比较差,也会影响后期维护,也比较容易出现bug.比如: 假设状态对 ...

  10. 6步快速配置Tomcat环境变量(Win10)

    一.配置 tomcat环境变量之前先安装jdk和配置jdk的环境变量 1.首先右击我的电脑(此电脑),点击属性,或者也可以从控制面板上打开,如下图,找到系统点击高级系统设置: 2.然后进入系统属性界面 ...