#include<iostream> using namespace std; int main() { cout << "hello world" << endl; //输出文字 system("pause"); // 方便观察结果 return 0; }
写xxx.h时,防止头文件重复包含
#ifndef AAA #define AAA #endif
命名空间
功能:区分同名变量或函数
创建 :namespace name { code}
namespace SortTestHelper{ }
使用方法
using namespace name;
name::变量名/函数;
:: 作用域运算符
3. using name::成员;
指定开放某个特定成员
运算符 | 说明 | 范例 | 结果 |
---|---|---|---|
= | 将一个表达式的值赋给另一个 | C = A + B | C = A + B |
+= | 相加后再赋值 | C += A | C = C + A |
-= | 相减后再赋值 | C -= A | C = C - A |
*= | 相乘后再赋值 | C *= A | C = C * A |
/= | 相除后再赋值 | C /= A | C = C / A |
%= | 求余后再赋值 | C %= A | C = C % A |
运算符 | 说明 | 范例 | 结果 |
---|---|---|---|
<<= | 左移后赋值 | C <<= 2 | C = C << 2 |
>>= | 右移后赋值 | C >>= 2 | C = C >> 2 |
&= | 按位与后赋值 | C &= 2 | C = C & 2 |
^= | 按位异或后赋值 | C ^= 2 | C = C ^ 2 |
|= | 按位或后赋值 | C |= 2 | C = C | 2 |
cin遇到空格或回车停止。
#include
#include
using namespace std;
int main()
{
char a[50];
cin>>a;
cout<<a<<endl;
return0;
}
输入:abcd遇回车输出abcd
缺点:只能输入没有空格的字符串,当输入中含有空格,则只能输出空格之前的字符
输入:“Hello world"输入空格时输入并未停止,遇回车输入停止,输出"Hello”,空格及空格后面的均未输出。
可以无限读取,以回车结束读取,C语言中的函数,在C++中运行会产生bug。
#include
#include
using namespace std;
int main()
{
char a[50];
gets(a);
cout<<a<<endl;
return0;
}
输入:“Hello world"回车结束输入,输出结果为"Hello world”。
istream& getline(istream& is,string& str,char delimiter='\n') 第一个参数是输入流, 第二个参数是字符串变量, 第三个参数是分隔符,默认分隔符是'\n'。
若定义变量为string类型,则要考虑getline()函数。用法如下:
#include
#include
using namespace std;
int main()
{
string a;
getline(cin,a);
cout<<a<<endl;
return 0;
}
输入:"Hello world"回车结束输入,输出结果为:“Hello world”
cin.get()函数可以接收空格,遇回车结束输入。
#include
using namespace std;
int main()
{
char a[50];
cin.get(a,50);
cout<<a<<endl;
return 0;
}
输入:“Hello world"回车结束输入,输出结果为"Hello world”
cin.getline()函数可以同cin.get()函数类似,也可接收空格,遇回车结束输入。
#include
using namespace std;
int main()
{
char a[50];
cin.getline(a,50);
cout<<a<<endl;
return 0;
}
输入:“Hello world"回车结束输入,输出结果为"Hello world”
输入一行,并以空格隔开,空格处理可以留给cin去除,cin.get()主要判断是否换行(输入结束),代码如下:
//存入动态数组 int x; vector<int> vec; while (cin >> x) { vec.push_back(x); if (cin.get() == '\n')//下一个为换行符,就不再获取 break; } for (int i = 0; i < vec.size(); i++) { cout << vec[i]; } //存入静态数组 int x[10005]; int i = 0; int n; while (cin >> n) { x[i] = n; i++;//最后的i值等于输入的个数 if (cin.get() == '\n') break; } for (int j = 0; j < i; j++) { cout << x[j]; }
eg:输入数据为1 5 6 7,vec中的数据为{1, 5, 6, 7}。
cin.get()
也可以用getchar()
替换,但getchar()
是C语言的函数cin是C++的标准输入流,其本身是一个对象,并不存在返回值的概念。
不过经常会有类似于 while(cin>>a) 的调用,这里并不是cin的返回值,应该关注">>"输入操作符,其实是它到底返回了什么
“>>”操作重载函数istream& operator>>(istream&, T &);的返回值,其中第二个参数由cin>>后续参数类型决定。
其返回值类型为istream&类型,大多数情况下其返回值为cin本身(非0值),只有当遇到EOF输入时,返回值为0。
所以会有以下这种cin连续读取的方法
1 cin >> x >> y;
让数字字符去减‘0’得到的就是数字的值。
vector<int> isbn; char c='10'; isbn.push_back(int(c - '0'));
itoa()函数把整数转换成字符串,并返回指向转换后的字符串的指针。
三个参数如下:
int i = 48; cout << char(i);//0 char c[10]; cout << itoa(i, c, 10);//48
atoi()——把字符转换成整型数
char c = '0'; cout << int(c);//48 cout << atoi(&c);//0
有一个数组a,则数组名a就是数组首元素的地址,即
a=&a[0]
所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。
在 C++ 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:
type arrayName [ arraySize ];
在 C++ 中,您可以逐个初始化数组,也可以使用一个初始化语句,如下所示:
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0}; int a[26]={0};//初始化全为0
大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。
如果您省略掉了数组的大小,数组的大小则为初始化时元素的个数。因此,如果:
double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
您将创建一个数组,它与前一个实例中所创建的数组是完全相同的。
arr[3]=*(arr+3)
int arr[]={1,2,3}; int a=4; arr[3]=10; cout << arr[3]; //输出 //10
上述代码中[]
就是进行了下标运算,数组arr和a依次被定义,他们被安排在同一块内存空间的相邻位置,且都为int型,那么arr[3]实际指向的是a的内存空间,因此a被改写
C++独有
#include <iostream> using namespace std; struct Node { int i; //可以放函数成员 void fun() { cout << "我是struct" << endl; } }; int main() { Node a;//声明变量可以不用struct关键字 a.i=10;//初始化a中的变量 a.fun();//调用a中的方法 system("pause"); return 0; }
结构体是特殊的类:除了定义时有一些不同,其他貌似没什么区别
定义结构体:struct 名称{};
定义类:class 名称{};
结构体与类中都能写成员变量和成员方法
创建对象都是:名称 变量名;
给成员变量赋值都是:变量名.成员变量
new
——申请空间//失败返回一个NULL,同C语言的malloc一样 int *p = new int; int *p = new int(10); //初始化一个值 struct Node{code;}; Node *p = new Node; int *p = new int[10]; //申请数组空间
delete
——释放空间delete p; <==> new type;
delete [ ] p;<==> new type [count];
delete NULL 是安全的, free(NULL)会崩溃
指针的大小
地址+1 是加了一个类型的大小
64bit编译器——8字节
32bit编译器——4字节
*的三种作用(C/C++)
int *p
函数存放在内存的代码区域内,它们同样有地址.如果我们有一个 int test(int a) 的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。
int (*fp)(int a); // 这里就定义了一个指向函数(这个函数参数仅仅为一个 int 类型,函数返回值是 int 类型)的指针 fp。
int b = 12; int &c = b; //c是b的引用 int &d = b; //d是b的引用 int &e = d; //e是d的引用
const int &n = 12; const char &c = 'a'; const float &f = 123.123f;
int a[2]; int (&b)[2] = a; int a[2][3]; int (&c)[2][3] = a;
方式同数组指针一样
类型 & 名字 = 结构体实例;
int* p = NULL; int* (&d) = p;
声明,定义
默认参数只能放在形参列表的最后,而且一旦为某个形参指定了默认值,那么它后面的所有形参都必须有默认值
全部指定:int fun(int a = 0, char c = 'b', float f = 12.12 );
部分指定:int fun(int a , char c = 'b', float f = 12.12 );
从右向左逐个指定
如果声明与定义时分开的,那么声明可以有默认值,定义不可以有默认值
函数名字相同,参数列表不同
void fun(int a); void fun(int a, int b); void fun(char c); void fun(float f, double d);
系统会根据参数的形式,自动找到要调用的函数
class是一种类型,只有在创建对象时才会分配内存空间
class 类名 { };
1. 栈区普通对象
CPeople op; 1)显示调用: Stock food = Stock("360",250,2.5); 2)隐式调用; Stock food("360",250,2.5);
2. 堆区指针对象(new出来的东西都在堆中)
CPeople* op1 = new CPeople;
除了静态成员,都要使用对象来调用
//对象.成员 op.Test();
指针对象要使用指针操作符
new完之后要记得delete
//对象->成员 op1->Test(); delete op1;
private
类内可见
类内不写访问修饰符,默认是private
protected
类内以及子类可见
public
类外可见
C++的结构体默认是public
friend(友元)
友元可以在类中直接定义,也可以只声明,然后在类外定义
友元函数可以访问类的所有成员(包括private、protected)
友元函数并不是成员函数
相同class的各个objects互为friends(友元)
友元函数
friend void fun(); friend int main();
友元类
friend class xxx
使用protected成员有两种方法
使用private成员只能用友元
特点
类名(参数列表){} //因为返回的必然是当前类的对象,所以不写即可
创建对象时会自动调用构造函数
栈区普通对象
堆区指针对象
声明指针并不会调用构造函数,只有new空间的时候才调用
多个构造函数构成重载
只有构造函数才有初始化列表
数据在构造函数中有两个状态,先是初始化,后是赋值
初始化是一个变量或者对象产生之时就赋予一个初始值,伴随性质
赋值是一个变量或者对象产生之后的任意时刻可以赋予一个值,随意性质
对于引用,const:只能初始化,不能赋值
构造函数之后加个冒号:a(1),b(2)
成员初始化顺序,只与声明顺序有关,与初始化列表书写顺序无关
class MyClass { public: int a; int b; MyClass() : b(1),a(2)//a先初始化为2,b再初始化为1 { a=2;//赋值 b=3; } };
const在函数名前面的时候修饰的是函数返回值
const在函数名后面表示是常成员函数,该函数不能修改对象内的任何成员,只能发生读操作,不能发生写操作。
class Test(){ public: Test(){} const int foo(int a); const int foo(int a) const; };
我们都知道在调用成员函数的时候编译器会将对象自身的地址作为隐藏参数传递给函数,在const成员函数中,既不能改变this所指向的对象,也不能改变this所保存的地址,this的类型是一个指向const类型对象的const指针。
https://www.runoob.com/w3cnote/cpp-inline-usage.html
解决了一些频繁调用的小函数大量消耗栈空间(栈内存)的问题
定义在类中的成员函数默认都是内联的,关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用
inline const char *num_check(int v) { return (v % 2 > 0) ? "奇" : "偶"; }
上面的例子就是标准的内联函数的用法,使用 inline 修饰带来的好处我们表面看不出来,其实,在内部的工作就是在每个 for 循环的内部任何调用 num_check(i) 的地方都换成了 (i%2>0)?“奇”:“偶”,这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗。
value有多少字节,就将多少字节进栈,不推荐使用
test(int i){}
C语言中是靠指针来解决这个问题的,当value太大,那我们传递它的地址即可
C++中的引用相当于指针,但比指针更快,因此所有参数传递建议都使用引用,返回值亦是如此
引用相当于给变量起的别名,因此在函数中修改引用的话,外部的value也会改变。
当我们不想value发生改变时,可以使用const关键字
test(int& i){} test(const int& i){}
在C++中的操作符重载有两种形式,一种是在类内声明public
函数实现操作函重载(这种情况下,操作符是作用在左操作符上的);另一种是在类外声明全局函数实现操作符重载.
操作符就是一个函数,可以通过重载重新定义,且有两种重载方式,一是写成成员函数,二是写成非成员函数(全局函数)
在类或结构体内定义成员函数来重载操作符
class complex { public: complex (double r = 0, double i = 0): re (r), im (i) { } complex& operator += (const complex&); private: double re, im; };
inline complex& __doapl (complex* ths, const complex& r) { ths->re += r.re; ths->im += r.im; return *ths; } inline complex& complex::operator += (const complex& r) { return __doapl (this, r); }
complex c1(2, 1); complex c2(4, 0); c2+=c1
编译器执行c2+=c1
时,编译器会把操作符作用于左边的c2,即把右边加到左边,所以可以返回引用
所有成员函数的参数列表都携带一个隐藏的this指针
complex::operator += (this,const complex& r)
this指针指向当前函数的调用者(一个对象),即“谁调用我,我就是谁”。那么return *ths
是返回ths所指向的对象(取地址的值),用引用来接收
this不能在参数列表中写出,但在函数内部可以使用
inline complex operator + (const complex& x, const complex& y) { return complex (real (x) + real (y), imag (x) + imag (y)); } inline complex operator + (const complex& x, double y) { return complex (real (x) + y, imag (x)); } inline complex operator + (double x, const complex& y) { return complex (x + real (y), imag (y)); }
上面这些函数不可能返回引用,因为返回的是个局部变量,生命周期和所在函数一样,所以我们要直接返回值
temp object 临时对象:
typename ()
匿名临时对象,生命周期只维持一行
#include <iostream> using namespace std; class Stu{ public: int age; int score; Stu(){ age=12; score=666; } }; void operator + (Stu& s,int a){ cout << s.age+a << endl; } int main() { Stu a, b; a+2;//14 return 0; }
cout << c1;
操作符<<作用于左边(C++中操作符都作用于左边,不会作用于右边),且只能重载为全局函数,不能是成员函数
操作符重载一定作用于左边操作符身上