C++基础

1.c++基础

1.c++ HelloWord

#include <iostream>
using namespace std;

int main()
{
    cout << "Hello World!\n";//cout为输出流,cin为输入流
}

2.自定义类型

auto:编辑器通过初始值自动推断变量类型

decltype:定义一个变量与某一表达式的类型相同,但并不用该表达式初始化变量

enum Game {WIN=0,LOSE,,TIE,CANSEL}; //枚举定义
//1.枚举元素是常量,不能对他们赋值
//2.枚举元素拥有默认值,默认从0开始依次递增
//3.可以在声明时另行指定枚举元素的值 *
//4.枚举值可进行关系运算
//5.整数值不能直接赋给枚举变量。如需将整数赋值给枚举变量,应进行强制类型转换
//6.枚举值可以赋值给整型变量
auto val = val1 + val2; //val1+val2为int类型则val也为int类型
decltype(i) j = 2; //表示j初始值为2,但类型与i一致

3.函数的参数传递

  1. 在函数被调用时才分配形参的存储单元
  2. 实参可以是变量,常量或表达式
  3. 实参类型必须与形参相符
  4. 值传递是传递参数值,即单向传递
  5. 应用传递可以实现双向传递
  6. 常引用做参数可以保障参数数据的安全 *

4.引用类型

引用(&)是标识符的别名

定义一个引用时,必须同时对他进行初始化,使它指向一个已存在的对象

一旦一个引用被初始化后,就不能改为指向其他对象

int i,j;
int &ri = i; //定义int引用ri,并初始化为变量i的引用
j = 10;
ri = j; //相当于i=j
#include <iostream>
using namespace std;
//x=10,y=20
void swap1(int a,int b) {
	int temp;
	temp = a;
	a = b;
	b = temp;
}
//x=20,y=10
void swap2(int &a, int &b) {
	int temp;
	temp = a;
	a = b;
	b = temp;
}

int main() {
	int x = 10;
	int y = 20;
	//swap1(x, y);
	swap2(x, y);
	cout << "x: " << x << " y: " << y << endl;
	return 0;
}

5.内联函数

内联函数体内不能有循环语句和switch语句

内联函数的定义必须出现在内联函数第一次被调用之前

对内联函数不能进行异常接口声明

//相当于将函数直接嵌入在调用的地方,可以减少转子函数的开销
inline double calCapcity(double heigh, double width) {
	return heigh * width;
}

6.对象的定义

//声明类,属性,构造方法
class Clock {
public:
	Clock();
	Clock(int h, int m,int s);
    //复制构造函数(默认值赋值)
    Clock(const Clock &c) {
		hour = c.hour;
		minute = c.minute;
		second = c.second;
	};
    //析构函数(对象被销毁前调用,默认空实现)
    ~Clock(){};
private:
	int hour, minute, second;
};
//委托构造函数
Clock::Clock() : Clock(0, 0, 0) {}

//是下面构造函数的简写
Clock::Clock(int h, int m, int s) :hour(h), minute(m), second(s){}

Clock::Clock(int h, int m, int s) 
{
    hour=h;
    minute=m;
    second=s;
}

7.结构体

结构体是一种特殊形态的类。

与类的唯一区别:类的缺省访问权限是private,结构体的缺省访问权限是public

struct 结构体名{
    //公有成员
protected:
    //保护类型成员
private:
    //私有成员
}

8.联合体

成员共用同一组内存单元

任何两个成员不会同时有效

union 联合体名{
    //公有成员
protected:
    //保护类型成员
private:
    //私有成员
}

9.枚举类

枚举类优势

1.强作用域,其作用域限制在枚举类中。example:Type::General

2.转换限制,枚举类对象不可以与整型隐式的互相转换

3.可以指定底层类型

//enum class 枚举类名:底层类型{枚举值};
enum class Type {General,Light,,Medium};
enum class Type:char {General,Light,,Medium};
enum class Type {General=1,Light,,Medium};

10.静态数据成员

用关键字static声明

为该类的所有对象共享,静态数据成员具有静态生存期

必须在类外定义和初始化,用(::)来指明所属的类

11.类的友元

友元是C++提供的一种破坏数据封装和数据隐藏的机制

通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息

可以声明友元函数和友元类

为了确保数据的完整性,及数据封装与隐藏的原则,必须谨慎使用友元

1.友元函数

友元函数是在类声明的中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象名访问private和protected成员

作用:增加灵活性,是程序员可以在封装和快速性方面做合理选择

访问对象中的成员必须通过对象名

12.指针

1.内存空间的访问方式

通过变量名访问

通过地址访问

2.指针的概念

指针:内存地址,用于间接访问内存单元

指针变量:用于存放地址的变量

static int i;
//初始化
static int* pti = &i;
*pti = 10;

3.与指针相关的运算

指针运算符:*

地址运算符:&

4.指针的初始化

语法形式:存储类型 数据类型 *指针名=初始地址;

注意事项:用变量地址作为初始值时,该变量必须在指针初始化之前已声明过,且变量类型与指针类型一致。可以用一个已有合法值的指针去初始化另一个指针。不要用一个内部非静态变量去初始化static指针

5.指针变量的赋值运算

语法形式:指针名=地址

注意:

1.“地址”中存放的数据类型与指针类型必须相符,向指针变量赋的值必须是地址常量或变量,不能是普通整数。(通过地址运算“&”求得已定义的变量和对象的起始地址,动态内存分配成功时返回的地址)

2.例外:整数0可以赋给指针,表示空指针。(C++11使用nullptr关键字表示空指针,是表达准确,类型安全的空指针)

3.允许定义或声明指向void类型的指针。该指针可以被赋予任何类型对象的地址

6.指向常量的指针

不能通过改变常量的指针改变所知对象的值,但指针本身可以改变,可以指向另外的对象

int a;
const int *p1=&a;//p1是指向常量的指针
int b;
p1 = &b; //正确,p1本身的值可以改变
*p1 = 1;//编译错误

6.指针类型的常量

若声明指针常量,则指针本身的值不能被改便。

int a;
int * const p2 = &a;
int b;
p2 = &b; //错误

2.c++高级

1.Vector

封装任何类型的动态数组,自动创建和删除

数组下标越界检查

#include <iostream>
#include <vector>
using namespace std;

double average(const vector<double>& arr) {
    double all = 0;
    int size = arr.size();
    //for (unsigned i = 0; i < size; i++) {
    //    all += arr[i];
    //}
    //基于范围的for循环
    for (auto i: arr) {
        all += i;
    }
    return all / size;
}

int main() {
    unsigned n;
    cout << "n= ";
    cin >> n;
    vector<double> arr(n);
	cout << "Please input" << n << "realNum" << endl;
    for (unsigned i = 0; i < n; i++) {
        cin >> arr[i];
    }
    cout << "Average = " << average(arr) << endl;
    return 0;
}

2.移动构造

c++11引入移动语义:原对象资源的控制权全部交给目标对象

#include<iostream>  
using namespace std;
class IntNum {
public:
    IntNum(int x = 0) :ptr(new int(x)) {//构造函数  
        cout << "Calling constructor..." << endl;
    }
    IntNum(const IntNum& n) :ptr(new int(*n.ptr)) {//复制构造函数  
        cout << "Calling copy constructor..." << endl;
    }
    IntNum(IntNum&& n) :ptr(n.ptr) {//移动构造函数
        n.ptr = nullptr;
        cout << "Calling move constructor..." << endl;
    }

    ~IntNum() {//析构函数  
        delete ptr;
        cout << "Destructing..." << endl;
    }
    int getInt() { return *ptr; }//返回指针所指向的值,而不是返回指针本身  
private:
    int* ptr;
};

//返回值为IntNum类对象  
IntNum getNum() {
    //定义了一个局部对象,然后将局部对象作为结果返回  
    IntNum a;
    //返回值是IntNum类型  
    return a;
}
int main() {
    //getNum()函数返回了一个IntNum类型的对象(临时无名对象),之后调用类的函数  
    cout << getNum().getInt() << endl;
    return 0;
}

3.string类

4.继承与派生

默认情况下派生类包含了全部基类中除构造和析构函数之外的所有成员。c++11规定可以用using语句继承基类构造函数。

5.虚基类

6.运算符重载

c++几乎可以重载全部的运算符,而且只能够重载c++中已经有的。(不能重载的运算符: " . " , " .* " , " :: " , " ?: " )

重载之后运算符的优先级和结合性都不会改变

1.双目运算符重载规则

如果要重载B为类成员函数,使之能够实现表达式 oprd1 B oprd2,其中oprd1为A类对象,则B应被重载为A类的成员函数,形参类型应该是oprd2所属的类型。

经重载后,表达式oprd1 B oprd2相当于oprd1.operator B(oprd2)

2.后置单目运算符++和--重载规则

如果要重载++或--为类成员函数,使之能够实现表达式oprd++或oprd--,其中oprd为A类对象,则++或--应该被重载为A类的成员函数,且具有一个int类型形参。

经重载后,则表达式oprd++相当于oprd.operator++(0)

#include<iostream>  
using namespace std;

class Clock
{
public:
	Clock(int s, int m, int h) :second(s), minute(m), hour(h) {};
	Clock &operator ++() {
		second++;
		if (second >= 60) {
			second -= 60;
			minute++;
			if (minute >= 60) {
				minute -= 60;
				hour = (hour + 1) % 24;
			}
		}
		return *this;
	}
	Clock operator++(int) {
		Clock old = *this;
		++(*this);
		return old;
	}
	void showTime() {
		cout << hour << "时" << minute << "分" << second << "秒" << endl;
	}
private:
	int second, minute, hour;
};

int main() {
	Clock a(2, 5, 20);
	(a++).showTime();
	(++a).showTime();
}

7.虚函数

用virutual关键字说明的函数

虚函数是实现运行时多态性基础

c++中的虚函数是动态绑定的函数

虚幻书必须是非静态的成员函数,虚函数经过派生后,就可以实现运行过程中的多态

posted @ 2020-10-16 15:12  深陈  阅读(149)  评论(0)    收藏  举报