#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 << "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语言的学习,相信你已经对面向过程有所了解。假如我们现在要用程序来模拟一次上课的场景,用面向过程的思维来设计的话就是:
那如果我们要用面向对象的思维来模拟上课场景,该怎么做?
面向对象在台湾有另一种叫法——物件导向。所谓的对象其实就是我们常说的东西,对象可以是
一个对象由下面两样东西组成
Data
)Operations
)
以一盏灯为例
Properties
可以是灯丝,Status
是灯是否开启、灯的颜色。Operations
可以是开关,这个操作会改变内部的Data
上面这副蛋图,蛋黄位置的Data
被Operations
所包裹。想要碰到Data
只能穿过Operaions
。
为什么要把Data
包裹起来?举个栗子,电视机的外壳。这个外壳除了让产品更好看之外,更重要的是保护着电视内部的电气元件,通常外壳上都会贴一个警告标签
非专业人士请勿拆卸
显然厂家不希望用户拆开这个外壳,如果用户拆开了外壳,自己去拔插电视内部的线路,很有可能会损坏电视。
但这个外壳会影响我们的使用吗?当然不会,设计者留出了很多按钮开关来操作电视机,这些按钮开关就是我们说的Operations
。
在OOP的世界里,大致有两类程序员
对于设计者来说,用户不能直接碰到内部数据。用户只能通过设计者给出的接口来访问内部数据。
对于用户来说,用户关心的是功能而不是原理。正如电视机的按钮,按下就可以启动,用户不需要了解其中的电子电路知识。设计者对用户屏蔽了具体实现细节。
把数据和数据的操作放在一起,形成有机联系,叫做封装。
所以,如果我们要用面向对象思维来模拟一个上课过程,我们要做的就是写对象
这些对象的互动就是上课的过程。
a collection of things sharing a common attribute.
entity
object
是实体,class
是概念
小明是一个学生对象,他的名字是 小明
,期末考成绩90
从小明身上抽象出学生的一些共有属性,可以得到下面的类
class Student{
int sid;
int score;
};
另外有一个学生对象小红
,她也会有学生类里面的属性
所以,class
定义了object
该长什么样,而object
里面有具体的属性。
一个特定类型的对象可以接受相同的信息。反过来也可以说,能接受相同消息的对象可以认为是一样的对象。
//这是一个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
,那么这个成员可以被类外面的语句、函数随便使用。以Student
类为例,其全部成员声明为public
,可以直接修改zs
的数据
Student zs;
zs.sid = 007;
改写Student
class Student{
private:
int sid;
int score;
public:
void haha( void ){
cout << "haha..." << endl;
}
};
现在sid
和score
是这个类所私有的成员,此时不允许在外部用zs.sid = 007
来修改内部数据,必须是类里面的成员才能修改它们。
class Student{
private:
int sid;
int score;
public:
void haha( void ){
cout << "haha..." << endl;
}
void get_sid( void ){ //修改sid的接口
cin >> sid;
}
};
如果省略了public
和private
关键字
struct
默认全部成员公开class
默认全部成员私有在C99之前,C语言是没有表示真假的布尔值,统统用int
#define TRUE 1
#define FALSE 0
int flag = 5 > 3;
flag
的值只有0
和1
两种情况
C语言把非0
当作真,0
当作假,在C++也是一样的
//测试用例
if (3) {
cout << 1 << endl;
}
if (-2) {
cout << 2 << endl;
}
//屏幕输出
1
2
C++提供了bool
型变量,bool
只占用一个字节的空间,用true
和false
这两个字面值常量来表示真假。
bool flag = true;
flag = false;
用int
类型的数据来给bool
类型赋值时
非0的认为是true
0认为是false
bool flag = 123;
cout << flag << endl;
//屏幕输出
1
C++是一门强类型的语言,声明变量的时候必须清楚地知道表达式的类型,然而要做到这一点并非容易。
auto
关键字让编译器自己去推断类型。和int
这些特定类型不同,auto
定义的变量必须有初始化。
auto a = 3;
a /= 2;
cout << a << endl;
//屏幕输出
1
用3
来给a
初始化,编译器推断a
为int
auto a = 3.0;
a /= 2;
cout << a << endl;
cout << sizeof(a) << endl;
//屏幕输出
1.5
8
用3.0
给a
初始化,编译器推断出a
为double
类型。
引用是已经定义的变量的别名
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)
的值为3
,3
是一个常量,常量不能做左值
在C++,(a = 3)
是a
的引用,可以继续赋值。
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]
C++可以编译下面的代码
int add( int x, int y );
int add( int x, int y, int z );
有两个函数名相同但参数列表不同的函数,在编译时编译器就会选取符合参数列表的函数。
但下面的代码不能通过编译
int add( int x, int y );
int add( int y, int z );
虽然参数的名字不相同,但两者的原型是一样的,都是
int add( int, int );
无法重载。
下面的代码也不能通过编译
int add( int x, int y );
void add( int x, int y );
仅仅是返回类型不一样,编译器无法判断究竟重载哪个函数。
无法重载。
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;
}
auto f = []( int a, int b )-> int{ return a + b; };
这是函数的一种写法
( int a, int b )
是参数列表{}
前面写函数的返回类型{}
里面写函数的内容。命名空间可以帮助我们避免不经意的名字定义冲突,以及使用库中相同名字导致的冲突。标准库定义的所有名字都在命名空间std
中。
通过命名空间使用标准库,当使用标准库中的一个名字时,必须使用::
显式说明。
std::cout << "Hello World!" << std::endl;
要使用命名空间,头文件iostream
不能有.h
using
编译指令使得std
命名空间里的所有名称都可用
之后都不需要使用std::
手机扫一扫
移动阅读更方便
你可能感兴趣的文章