C++基础

环境VS

1. 数据类型

int 4字节

char 1字节

bool 1字节

float 4字节 保留7位 指数38位

double 8字节 15位

long double 8字节 保留15位  指数38位

short int or short 2字节

long int or long 4字节

unsigned int 

signed int 首位为1

 

*数组的动态声明:

1维:

int *a = new int[n]; //生成长度为n的数组;

int *a = new int(n); // 如果n=5, *a  ( a[0]) 会返回5; 

char *q = new char[10](); //生成长度为10的数组,并赋初值均为0;

delete [] a; //释放掉申请的存储空间 普通变量为 delete a;

 

2维(n行m列):

int **a = new int*[n];
    for(int i=0;i<n;i++){
        a[i] = new int[m];
    }

int & b = a; //b 是 a的 别名,对b操作a跟着变;

常数e.g.      const  double PI=3.14159;当前函数内有效,且不可改变。

                   static double  PI=3.14159; 当前函数内有效,可改变,且运行完当前函数不释放。

                   #define N 5;始终有效,可改变。 #undef N 来取消定义。

 

#include<memory> //智能指针

shared_ptr<int> a1(new b[3]); //效果等同于 int* a2 = new b[3]; 但是 a1 != a2;

 

对数组内每个数操作:

int a[3]={1,2,3};

int b = sizeof(a)/sizeof(a[0]);

for (int i=0;i<b;i++){ 操作a[i] }  // 也可 for(int & e : a) {操作e },不想变a内值则 int e 足矣

 

无序容器(哈希表):

#include<unordered_map>

unordered_map<string,int> winnner;

winner.insert(make_pair("bb",1999));

winnner["cc"]=1998;

 

正则表达式:

#include<regex>

regex reg("b.?p.*k");  //  .? 表示之间出现一个字符或者没有字符, .* 表示之间可以出现同一字符任意多次或0次

cout  << regex_match("bopggk",reg) << endl; //返回1

regex reg("\\d{3}([a-zA-z]+).(\\d{2}|N/A)\\s\\1"); // \\d{3} 表示以3个数字开头,  ([a-zA-z]+) 表示任意英文字符出现1次或n次, . 表示可以出现任意一个字符, (\\d{2}|N/A) 表示为2个数字或者"N/A", \\s 表示空格, \\1 表示第一项,可能非数字才算?

 

2. 进制转换

dec 十进制

oct 八进制 o

hex 十六进制 ox

%d 以10进制形式输出带符号整数(正数默认不输出符号)

%o 以8进制形式输出无符号整数(不输出前缀0)

%x(X) 以16进制形式输出无符号整数(不输出前缀ox)

%u 以10进制形式输出无符号整数

%f 以小数形式输出单、双精度实数

%e(E) 以指数形式输出单、双精度实数

%g(G) 以%e或%f中较短的输出宽度输出单、双精度实数

%c 输出单个字符

%s 输出字符串

 

强制类型转换:

int i;

i = 5;

float f;

f = (float) i;

 

3. 赋值运算

两边类型不同,自动完成 转换 。short int - int - long - unsigned int ->double <-float

长数赋给短数,直接截取低位送过去。

短数赋给长数,数不变。

符号位的处理,直接赋过去,因此可能首位变为符号。

运算符优先级:

! > && > ||

 

4.函数

函数名称前缀为返回值类型,void函数不允许有返回值。

5. 结构体变量&&内联成员函数

struct student{

int id;

char name[10];

}

 

main函数内:

student mike ={123,{'m','i','k','e','\0'}};

student *Nake=&mike;

此时 *Nake.id 等价于 Nake->id

 

内联成员函数,整个函数体出现在类定义内部:

inline int a(){

xxxxxx;

}

重载函数,参数个数不同或类型不同,可以为后面某个形参设默认值,即实参不设定次变量则默认为默认值

void valuex(x,x=2){};

void valuex(x,x,x){};

使用重载参数要避免函数二义性,即函数类型一样时(x,x=2); (x);这样只输入一个参数时无法断定属于哪个函数。

6.引用与指针

int a;

int & b = a; //b就是变量a的别名,b改a也跟着变

int *p =  &a; //p指向a所在的空间,p改a也跟着变

 

e.g. 在main函数中调用时,swap && swap 2 均能交换实参a,b的值,而调用swap3则不会交换实参值(仅在swap3内会交换两个变量的值,但是这俩变量是复制出来的占用不同的内存空间)。

void swap(int* a, int* b){
	int tem = *a;
	*a = *b;
	*b = tem;
}


void swap2(int & a, int & b){
	int tem = a;
	a = b;
	b = tem;
}


void swap3(int  a, int  b){
	int tem = a;
	a = b;
	b = tem;
}

 

7. 类(class)

 

类中".”和“->”主要用于访问类的成员,->主要用于类类型的指针访问类的成员,而.运算符,主要用于类类型的对象访问类的成员。 

比如:

class A
{public :int a}
A ma;

A *p=&ma;

那么指针p应使用->来访问成员a,比如p->a,而ma应使用.来访问,比如ma.a区别就在这里,凡是指针就使用->,对象就使用.运算符。

 

在类定义中定义的成员函数把函数声明为内联的,即便没有使用 inline 标识符也可以直接在类内定义函数。

在类外也可以使用范围解析运算符定义函数,但需要在类内声明:

double 【相比于类内定义多加的部分】->Box::getVolume(void)
{
    return length * breadth * height;

}

在类外定义构造函数时只需要 BOX:: BOX(xxxx);即可

class相比于struct在C++中的区别:类中private类型只能在成员函数中被使用。

如下面例子priate中length能被成员函数double getVolume(void);调用;而Public中getVolume(void)可以被main函数中xx.getVolume()所调用。

如果想改动private中的变量可以在Public中设置会修改到此private变量的 接口函数,从而在主函数中用 xx.接口函数 修改私有成员的值。

其他类或函数想使用当前类中private类型可以使用友元函数,e.g. friend  int xxx(); friend int BOX:: xxx();

友元类: A是B的友元类,则A的成员函数可以访问B的私有成员。友元类之间关系不能传递也不能继承。

继承:A继承B类,则B类为基类,A类为派生类,    继承 某类型(public, private, protect)就可以访问某类型中的变量或函数。

继承要注明继承方式,否则class默认private继承,struct默认public继承。

继承后子类包含自己对象加基类所有对象。

 

多态:为了能通过指针指向自身的对象, virtual void xxx(){};

可以在子类中void xxx(){};

B sample;

A & a = sample;

a.xxx(){}; //B是A的子类,如果xxx不是虚函数,则返回A中的xxx,否则返回B中的xxx。

通常基类中析构函数也要virtual,这样构造和析构顺序为 基-子--子-基。

 

如果整个函数体出现在类定义内部则其为内联函数,或者class中定义 inline double getVolume(void);

构造函数: 对对象进行初始化,如给成员变量赋初值。

类中如没有定义构造函数,编译器自动生成默认的无参数的构造函数。默认构造函数”被需要“的时候编译器才会合成默认构造函数。

对象生成时构造函数自动被调用。对象一旦生成,就再也不能在其上执行构造函数。

构造函数的方法名必须与类名相同。
构造方法是一种特殊的方法,具有以下特点。
(1)构造方法的方法名必须与类名相同
(2)构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型。
(3)构造方法的主要作用是完成对象的初始化工作,它能够把定义对象时的参数传给对象的域。
(4)构造方法不能由编程人员调用,而要系统调用。

(5)一个类可以定义多个构造方法,如果在定义类时没有定义构造方法,则编译系统会自动插入一个无参数的默认构造器,这个构造器不执行任何代码。

(6)构造方法可以重载,以参数的个数,类型,或排列顺序区分

一个类可以有多个构造函数。

e.g. double getVolume(void);

 

构造函数,复制构造函数与赋值函数区别

class BOX{

    int i,j;

  public:

    BOX(int d){ //构造函数

        i = d;

        cout << i << endl;

    }

    BOX(int m, int n){//构造函数的重载

        i = m;

        j = n;

    }

    void getNum(int p){ //内联成员函数

        i = p;

    }

}

int main(){

    BOX a;

    BOX b(a); //复制构造函数

    BOX b = a; //复制构造函数

    BOX p(3); //函数初始化

    p = 5; //类型转换构造函数,运行完会析构掉

    {   BOX t(6);  } //{ }为作用域,运行完作用域内的会被析构掉

    BOX c;

    c = a; //赋值函数

   \\析构顺序为 main函数中的对象消亡,然后static静态变量消亡,然后全局变量消亡。

    return 0;

}

拷贝构造函数是一个对象初始化一块内存区域,这块内存就是新对象的内存区,而赋值函数是对于一个已经被初始化的对象来进行赋值操作。

一般来说在数据成员包含指针对象的时候,需要考虑两种不同的处理需求:一种是复制指针对象,另一种是引用指针对象。拷贝构造函数大多数情况下是复制,而赋值函数是引用对象.

实现不一样。拷贝构造函数首先是一个构造函数,它调用时候是通过参数的对象初始化产生一个对象。赋值函数则是把一个新的对象赋值给一个原有的对象,所以如果原来的对象中有内存分配要先把内存释放掉,而且还要检察一下两个对象是不是同一个对象,如果是,不做任何操作,直接返回。

复制构造函数:

A a;

A b(a); //

a b=a; //

赋值函数:

A a;

A b;

b=a;

 

复制构造函数起作用的三个情况:

1. 用一个对象去初始化同类的另一个对象时。

Complex A2(A1);

Complex A2=A1;

2. 如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用。

void func(A a1){ }

int main(){

A a2;

void func(a2);

return 0;

}

3. 如果函数返回值是类A的对象时,则函数返回时,A的复制构造函数被调用。

A func( ){

A b(4);

return b;

}

int main( ){

cout << func().v << endl;

return 0;

}

析构函数

名字与类名相同

在前面加~

没有参数和返回值

一个类最多有一个析构函数

 

先构造的后析构,先析构的后构造。

 

 

静态成员变量

值所有成员共享,class A1 & class A2 .... 中都有相同的值。但是如果是私有的需要用public内的函数调用输出。

sizeof( class) 不会计算静态成员变量。

静态成员变量本质上是全局函数。

必须在定义类的文件中对静态成员变量进行初始化。 int BOX:: len=0; 不过可以不初始化成指定的值。

在静态成员函数中,不可以访问或者调用非静态成员变量或函数。

静态成员函数不具体作用于某一个对象 (A1.xxx() , A2.xxx() 虽可如此调用,但是不作用于A1 & A2),可以用类名:: 成员名调用(BOX:: xxx();),静态成员变量也可如此调用; 也可用普通方法调用 BOX a; a.xxx(); ;也可用指针调用 BOX* p = &a; p->xxx();

封闭类:

成员对象:一个类的成员变量是另一个类的对象。

封闭类:包含成员对象的类。

封闭类需要定义构造函数,不然编译器不知道类内的其他类(对象)该怎么初始化。

 

定义封闭类的构造函数可以用初始化列表:

Ccar:: Ccar(int i, int j, int k): price(i), tyre(j,k) { }; Ccar为封闭类,tyre为另一个类。

 

this指针:指向成员函数所作用的对象,通常为this->

 

类的使用例子:

#include <iostream>
using namespace std;

class Box
{
    
   private:
      double length;         // 长度
      double breadth;        // 宽度
      double height;         // 高度
   public:
      // 成员函数声明
      double getVolume(void);
      void setLength( double len );
      void setBreadth( double bre );
      void setHeight( double hei );
   Box operator+(const Box& b){....}; //重载运算符
};
// 成员函数定义
double Box::getVolume(void){    
return length * breadth * height;}
void Box::setLength( double len ){    
length = len;}
void Box::setBreadth( double bre ){    
breadth = bre;}
void Box::setHeight( double hei ){    
height = hei;}
// 程序的主函数
int main( ){   
Box Box1;                // 声明 Box1,类型为 Box   
Box Box2;                // 声明 Box2,类型为 
Box   double volume = 0.0;     // 用于存储体积    
// box 1 详述   
Box1.setLength(6.0);    
Box1.setBreadth(7.0);    
Box1.setHeight(5.0);   
// box 2 详述   
Box2.setLength(12.0);    
Box2.setBreadth(13.0);    
Box2.setHeight(10.0);   
// box 1 的体积   
volume = Box1.getVolume();   
cout << "Box1 的体积:" << volume <<endl;  
// box 2 的体积   
volume = Box2.getVolume();   
cout << "Box2 的体积:" << volume <<endl;   
return 0;
}

 

* Template 函数模板

为了使函数可以适应不同类型参数

template<class T>

void swap(T & a, T & b){

    T tem = a;

    a = b;

    b = tem;

}

main函数中可以swap(3,4);

 

template<class T1, class T2> 类模板

 template<class T1, int p> etc.

class pair{

public:

pair( T1 k, T2,v){};  

};

pair <string,int>  a("student",5); 模板类实例,赋形参时需定义好模板内类型。

 

按 C++ 标准来说,template<typename T> 用于基础数据类型,typename 指类型名,T 可以取 char int double 等。
实际上template<class T> 的 T 也可以取基础数据类型,tempate<typename T> 的 T 也可以取类。 

但有一个特例,就是当 T 是一个类,而这个类又有子类(假设名为 innerClass) 时,应该用 template<typename>:

typename T::innerClass   myInnerObject; 不然用class会报错。

 

* typedef 可以定义类型的别名。

1. typedef char* AAA;

AAA b, c; 则为两个字符指针。传统的 char*b,c; 则只有一个。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值