回顾c++----一点笔记

内容谈不上深刻请高手绕道。

自以为c++学得不差,可是一到笔试立马现原形了。。。果断深刻反省啊!!重新阅读谭浩强的c++和林锐博士<高质量C++/C编程指南>对后者只恨相见晚。。。本文是我自己在阅读时的一些笔记,其中很多表述仅帮助理解不能认真,难免有错误请大家指正。

输入输出

putchar('a') 输出一个字符
a=getchar() 读取一个字符
scanf(格式控制,输出表列)

int a;float b;char c;  
sacnf("%d %f %c",&a,&b,&c);

printf(格式控制,输出表列)

控制

switch(grade)
{   case 'A': cout<<"85~100\n";break;
    case 'B': cout<<"70~84\n";break; 
    default: cout<<"error\n";break;
}
do{
    ...
}
while();

函数

函数中形参是实参的副本

内部函数

static int fun()

外部函数

extern int fun()声明成外部函数(默认
在要用的地方声明extern int fun()

函数的参数是数组

函数里面的对数组的修改反应到原值上,也就是说是引用方式实现,因此

void Test(char str[100]){
    cout<<sizeof(str);//得到指针大小32位4,64位8
    int a[10];
    sizeof(a)//虽然a也是指针但这里是数组的大小
}

变量

先看一下内存中的供用户使用的存储空间的情况。 这个存储空间可以分为 三部分,即:

  1. 程序区
  2. 静态存储区
  3. 动态存储区

C++中变量存储类别(storage class) 的属性。 存储类别指的是数据在内存中存储的方法。 存储方法分为静态存储和动态存储两大类。 具体包含4种:自动的(auto)、 静态的(static)、 寄存器的(register) 和外部的(extern)。 根据变量的存储类别,可以知道变量的作用域和存储期

float double

注意到浮点数在其中有舍入误差所以在比较浮点数时不能用等于

const float epsinon=0.000001;

bool check(float x){
    if((x>=-epsinon)&&x<=epsinon){
        return true;
    }
    return false;
}

静态局部变量

例如在函数中static int c=3;

  • 在程序生命期内该内存不释放
  • 该句只执行一次
  • 对其他函数不可见

extern 声明外部变量

全局变量(外部变量)是在函数的外部定义的,它的作用域为从变量的定义处开始,到本程序文件末尾。 编译时将全局变量分配在静态存储区。有时需要用 extern 来声明全局变量,以扩展全局变量的作用域。

1.在一个文件内声明全局变量

void main(){
    extern int a,b;
    //use a,b.......//
}
int a=1,b=1;
//.....//

2.在多文件的程序中声明外部变量
这样使得两个文件共用一个变量

file1.cpp               file2.cpp
extern int a,b;         int a=3,b=4;
int main( ){
    //use a,b...//
}

静态外部变量

对上面的file2.cpp 使用static int则file1即使使用extern也不能访问file2的变量

和函数用法一样默认定义的都是可以外部调用的,在要调用的地方声明extern关键字

预处理命令

核心是原样代替

  1. 宏定义#define PI 3.14 #define S(a,b) a*b
  2. 文件包含
  3. 条件编译

     #ifdef 标示符 ||也可以用#if 表达式
     程序
     #else
     程序
     #endif 
    

指针

指针无处不在,数组就是指针

指针指向了一块内存单元。

数组

数组是一段连续的内存,有长度(应该是系统确定的)
初始化int a[3][4]={{1},{5},{9}};使用大括号


定义

int a[10];  
int *a=new int[10];  
int *a=new int(10);//这个是1个int并初始化为10  

访问

    ina a[10]; []可看做是变址运算符
    cout<<a;//得到的是内存地址,a是指针!但是有长度!
    sizeof(a)是40

    int *p;毫无疑问p是指向第一个元素的
    p=%a[0];等价于p=a;
    p+1就是a[i]的地址,*(p+1)就是元素a[i],指针法效率更高
    *(*(p+2)+3)==a[2][3]

    int (*p)[4]表示p指向数组,这里的大小要和被指向的数组一样。sizeof(p)得到的是指针大小
    PS:如果定义为char也可以用cout<<p<<endl;验证得到输出的是地址

由此得出数组是特殊的指针,包含了长度,其他的指针不包含长度

字符数组

char c[]="1234";在c[4]存在\0作为结束标志

奇葩的char

char的核心在于首地址和结束符\0

char x;//就一个字符,大小1
//下面是指针  
char x[]="xxx";//这个x是指针,但是sizeof(x)是数据的长度
char x[10];//char在使用时要指出大小,sizeof(x)为10,
char *x;//可以有指针,大小8/4


char a[]="1";被定义为char a[2]
char a[]={'1','2','\0','3','4'};
cout<<a<<endl;//和数组处理不一样啊,这里很正常地输出了12
char a[]="123\0123";
cout<<a;//输出 123换行3  此时char a[6]元素为1,2,3,\012,3,\0  由此可看出转义了三位
再测试,在\0后加空格则打印为123。由此可得遇到字符'\0'输出结束。转义符最多可转三位。 

x=new char(100);//动态空间用x指向就是个数组
用x[i]访问每个元素

i=3;
*i_p=3表示i_pointer指向的变量
int * p=&ip指向i,*p是i,*p是p所指向的单元

函数与指针

指向函数的指针int (*p)(int,int)*p定义为指针,指针指向函数

p=max;使用方法
p(a,b);  

指针函数就是返回指针的函数int *a(int x,int y) a先与()结合成函数

函数传入的参数是采用副本方式

void getMe(char *p){//这里的P是副本虽然指向原来位置
    cout<<p;
    p=NULL;
}
main
    char *p="123";
    getMe(p);
    cout<<p;//还是123
    cout<<*p;//1  注意首地址

指针的指针

char **p;
char *name[]={"basic","c++"};
p=name+1;
cout<<*p;//c++
cout<<**p;//c

同一数组中,两个指针可以相减得到之间元素个数,指针可比大小后面的大

引用

引用是声明别名声明完后就不能改了。引用能简化工作

void main(){                         void main(){
    void swap(int *,int *);                 void swap(int &,int &);
    swap(&a,&b);                            swap(a,b);
}                                     }
void swap(int *a,int *b){}            void swap(int &a,int &b){} 

结构体

struct Stu{
    int num;
    //....//成员列表
}stu1,stu2;//结构体变量
Stu *p=stu1;
(*p)=stu1
三种访问方式
    stu1.num 
    (*p).num
    p->num

结构体变量做函数参数和普通int用法都一样参见上面的函数部分。

共用体

共用体就是一个类型的集合,一次只能使用一个类型(一个成员),所占长度是里面MAX(成员长度)
举例:学生和老师,学生显示班级,老师显示职务,在表中同一字段一个int一个string

union data{//名称data可省略
    int i;
    char ch;
    double d;
}a,b,c;

枚举

enum aenum{a=2,b=1,c,d,e}w;//默认序号为前面+1,序号可以重复
在程序中能直接访问a,b,c,d
cout<<c;//c=2
switch (w) {
        case a:
            cout<<"a";
            break;
        case b:
            cout<<"b";
            break;
            //这里不能有c,因为识别成了2,重复

w只能是5个中的一个不能对w直接赋数字,w=aenum(2)或者w=c

动态分配内存

分配连续存储空间,返回指针,判断是否NULL

int* p=new int(10);//*(p+i)这样的方式访问,
       new char(3.14);//基本类型的
delete p;//普通
       new char[10];//数组类型
delete [] p;//对数组

typedef声明类型

typedef int INTEGER
声明结构体

typedef struct name{//name已经没意义了不用写
    int xx;
}data;//data是新的类型名,不是结构体的变量
data xxx;

OOP

封装:接口隐藏实现;继承:扩展旧接口;多态:相同接口的不同表现形态;

模板

函数模板

template<class T1,typename T2,typename T3> //模板声明,可多参。class和typename是类型名可以互换
T max(T1 a ,T2 b,T3 c){ //定义一个通用函数,用 T 作虚拟的类型名 
    ...}
int main( )
{   
    //...//
    i=max(i1,i2,i3); //调用模板函数,ix的类型映射到Ti
    //...//
}

类模板

template<class type1,class type2>
class a{
    public:
    type1 max(type2 aa){
        return aa;
    }
    type1 min(type2 bb);
};
//类外的定义
template <class type1,class type2>
type1 a<type1,type2>::min(type2 aa) {
    return aa;
}
//定义对象
a<int,float>obj;

函数重载

参数的个数和类型可以都不同。 但不能只有函数的类型不同而参数的个数和类型相同。

运算符重载

实质是函数的重载

class complex{
    complex operator+(complex &2);
};
complex complex::operator+(complex &2){
    return Complex(real+c2.real, imag+c2.imag);
    //或者如下
    complex c;
    c.real=real+c2.real;
    c.imag=imag+c2.imag;
    return c;
    ///
}

实际执行对象相加时编译器解释为
c1.operator+(c2)
可以把函数重载为非成员函数
friend Complex operator + (Complex &c1,Complex &c2);//要增加参数
解释为operator+(c1,c2)

构造函数

基本原理:注意到构造函数没有返回,意味着调用时使用this指针指向这个变量

class counter  
{  
public:  
    counter()  
    {  
        m_value =0;  
    }  
private:  
    int m_value;  
};  

对非内置类型成员变量,为了避免两次构造,尽量使用列表初始化
类类型的数据成员对象在进入函数体前已经构造完成,也就是说在成员初始化列表处进行构造对象的工作,调用构造函数,在进入函数体之后,进行的是对已经构造好的类对象的赋值,又调用个拷贝赋值操作符才能完成(如果并未提供,则使用编译器提供的默认按成员赋值行为)


但有的时候必须用带有初始化列表的构造函数:

  1. 成员类型是没有默认构造函数的类。若没有提供显示初始化式,则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数,则编译器尝试使用默认构造函数将会失败。
  2. const成员或引用类型的成员。因为const对象或引用类型只能初始化,不能对他们赋值。
    但是初始化表不能初始化静态成员,静态成员只能在类外初始化
class CExample {
public:
    int a;
    float b;
    //构造函数初始化列表
    CExample(): a(0),b(8.8)
    {}
    //构造函数内部赋值
    CExample()
    {
        a=0;
        b=8.8;
    }
};
构造函数可以是虚函数吗?

不可以,虚函数的执行依赖虚函数表,虚函数表在构造函数中进行初始化,即初始化虚指针,让他指向正确的虚函数表。构造函数,在构造对象期间,虚函数表尚未初始化,无法进行。

构造函数可以是内联函数吗?

可以,但是一般不要使用内联,因为构造函数很多情况下会有隐含动作(比如调用基类成员对象构造函数等)。

构造函数失败如何处理?

构造函数没有返回值,因此无法通过返回错误码来判断构造函数,最好办法应该是抛出一个异常。另外由于构造函数抛出异常时,析构函数就不会执行了,故同时还需要对已经执行的动作(如分配了内存、打开了文件、锁定了信号量等等)进行清理,将这些资源释放掉。


本文原创欢迎大家拍砖,转载请注明O(∩_∩)O谢谢。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值