C++中头文件中class的两个花括号后面要加上分号,否则会出现很多的莫名奇妙的错误。

一、

每一个C++程序(或者由多个源文件组成的C++项目)都必须包含且只有一个main()函数。对于预处理指令,如#include <iostream.h>为C语言风格的头文件,标准C++仍支持这种格式。但也可采用C++风格:#include <iostream>,但为了使iostream中的定义对程序有效,还需加上名称空间编译指令:using namespace std;//不要忘记分号。using是代码编译之前处理的指令。namespace为名称空间,它是标准C++的 一个新特性,用于解决程序中同名标识符(如同名函数)存在的潜在危机。

二、

/*…*/用于多行注释,//用于单行注释。每个预处理命令(宏定义,文件包含,条件编译)必须单独占用一行,且在尾部不能加分号,必须以#开始(#define,#include, #ifde f..#else..#endif,#if..#elif..#endif)。

三、

在C++中常用exit()和abort()函数来终止程序执行,exit(0)表示正常退出程序;exit(非0值)表示异常退出。

四、 try与catch、throw用法

(1)基础介绍

try语句块的作用是启动异常处理机制,侦测try语句块的程序语句执行时可能产生异常。如有异常则抛出异常(也可以直接用throw主动抛出异常)。

catch语句块用来捕捉try语句块产生的异常(包括用throw抛出的异常),然后进行处理。try总是与catch一同出现的,在一个try语句块之后,至少应该有一个catch语句块。catch语句块之前必须是try语句或另一个catch块。当catch中的整个形参为"..."时,表示catch能捕捉任何类型的异常。

try{...

throw value;                  //程序中主动抛出异常

}catch(形参类型[形参名])     //将异常值传入形参,并在catch块中使用该形参

{    ...

//异常处理语句

}

throw抛出异常值,catch接受(传入形参),此时throw必须在try语句块中才行。

(2)深入throw:

(i) 程序接受到throw语句后就会自动调用析构器,把该域(try后的括号内)对象clean up,然后再进入catch语句(如果在循环体中就退出循环)。这种机制会引起一些致命的错误,比如,当“类”有指针成员变量时(又是指针!),在“类的构建器”中的throw语句引起的退出,会导致这个指针所指向的对象没有被析构。这里很基础,就不深入了,提示一下,把指针改为类就行了,比如模板类来代替指针,在模板类的内部设置一个析构函数。

(ii)语句“throw;”抛出一个无法被捕获的异常,即使是catch(...)也不能捕捉到,这时进入终止函数

(3)深入catch:一般的catch出现的形式为

try

{...

}catch(except1 &)

{...

}catch(except2 &)

{...

}catch(...)   //接受所有异常

{...

}

一般都写成引用(except1&),原因很简单,效率。

抛出异常,但是catch不到异常怎么办?(注意没有java类似的finally语句)在 catch没有捕获到匹配的异常的时候,会调用默认的终止函数。可以调用set_terminate()来设置终止函数,参数是一个函数指针,类型是:void  (*terminate)()。

若没有try-catch,直接在程序中throw,会怎么样?导致程序终止

(4) try一个函数体,形式如下

void fun(type1,type2) try  //try放在函数体之后

{

//函数定义

}catch(type X)

{...}

这个用法的效果就相当于:

void fun()

{

try{函数定义}

}

(5)throw一个函数体,形式如下:

void fun (); //能抛出任何类型的异常

void fun () throw(except1,except2,except3)

{...} //后面括号里面是一个异常参数表,本例中只能抛出这3中异常

void fun () throw(){}  //参数表为空,不能抛出异常

假设fun()中抛出了一个不在“异常参数表”中的异常,会怎么样?

答:调用set_terminate()中设定的终止函数。然而,这只是表面现象,实际上是调用默认的unexpected()函数,然而这个默认的unexpected()调用了set_terminate()中设定的终止函数。可以用set_unexpected()来设置unexpected,就像set_terminate()一样的用法,但是在设定了新的“unexpected ()”之后,就不会再调用set_terminater中设定的终止函数了。这个语法是很有用的,因为在用别人的代码时,不知道哪个地方会调用什么函数又会抛出什么异常,用一个异常参数表在申明时限制一下,很实用。

(6)throw不一定出现在try语句块中,它可以出现在任何需要的地方,即使在catch块中,仍然可以继续使用throw,只要最终有catch可以捕捉它抛出的异常即可。当throw出现在catch块中时,通过throw既可以重新抛出一个新类型的异常,也可以重新抛出当前这个异常(此时,throw不应带任何实参)。

try

{   ...

}catch(int)

{

throw "hello exception";//抛出一个新的异常,异常类型为const char*

}catch(float)

{

throw;                  //重新抛出当前的float类型异常

}

五、

对于类中的public成员,它们是公有的,可以在类外访问;

对于protected成员,它们是半保护的,具有半公开性质,可在类中或子类中访问;

对于privated成员来说,它们是私有的,不能在类外访问,数据成员和函数成员只有由本类的其它函数成员定义时调用(对象都不能访问私有成员)。

需要说明的是,若一个成员函数的 声明和定义同时在类体中完成,则该成员函数不需要再单独定义,类体中定义的函数相当在类外定义的内联(incline)函数。如果所有的成员函数都在类体中定义,则在类外的成员函数定义可以省略。当类的成员函数的定义是在类体外部完成时,必须用作用域运算符::来告知编译器该函数所属的类。该类对象的成员访问方式与结构体访问成员相同,对象只能访问类中的公有成员,对于保护成员和私有成员均不能访问。

六、

类的构造函数,析构函数,赋值函数

(1)构造函数:该类对象被创建时,编译系统为对象分配内存空间,并自动调用该构造函数->由构造函数完成成员的初始化工作。 构造函数的作用:初始化对象的数据成员,构造函数的函数名与类名相同。构造函数一般有以下几种:

无参构造函数:example()。如果创建一个类你没有写任何构造函数,则系统会自动生成默认的无参构造函数,函数为空,什么都不做。只要你写了某一种构造函数,系统就不会再自动生成这样一个默认的构造函数,如果希望有一个这样的无参构造函数,则需要自己显示地写出来。

一般构造函数(也称重载构造函数):example(arg1,arg2...)。一般构造函数可以有各种参数形式,一个类可以有多个一般构造函数,前提是参数的个数或者类型不同(基于c++的重载函数原理)。创建对象时根据传入的参数不同调用不同的构造函数。

复制构造函数(也称为拷贝构造函数):example(const example &c)。复制构造函数的参数为本类其它对象的引用,用于根据一个已存在的对象复制出一个新的该类的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中。若没有显示的写复制构造函数,则系统会默认创建一个复制构造函数,但当类中有指针成员时,由系统默认创建该复制构造函数会存在风险,具体原因请查询 有关 “浅拷贝” 、“深拷贝”的文章论述。系统创建的默认复制构造函数只会执行“浅拷贝”,即将被拷贝对象的数据成员的值一一赋值给新创建的对象,若该类的数据成员中有指针成员,则会使得新的对象的指针成员所指向的地址与被拷贝对象的指针成员所指向的地址相同,delete该指针时则会导致两次重复delete而出错。此时应该自己定义复制构造函数,在复制构造函数中用new为新对象的指针成员指重新开辟一块内存,然后用strcpy函数将被拷贝对象的指针成员所指向的内容拷贝到新内存中去,这样则新创建的对象的指向新内存地址的指针成员与原对象的指针成员就不再指向同一地址了。

example(const example & c)

{
                // 将对象c中的数据成员值复制过来,函数中可以直接访问对象c的私有成员
                m_real =
c.m_real;
                m_img =
c.m_img;
           }

类型转换构造函数:example(double c)。根据一个指定的类型的对象创建一个本类的对象。前面将根据一个double类型的对象创建了一个example对象。

void main()

{
           // 调用了无参构造函数,数据成员初值被赋为0.0
           example c1,c2;
   
           // 调用一般构造函数,数据成员初值被赋为指定值
           example c3(1.0,2.5);
           example c3 = example(1.0,2.5); // 另一种形式
       
           // 把c3的数据成员的值赋值给c1
           // 由于c1已经事先被创建,故此处不会调用任何构造函数,只会调用 = 号运算符重载函数(赋值函数)
           c1 = c3;
          // 调用类型转换构造函数
          // 系统首先调用类型转换构造函数,将5.2创建为一个本类的临时对象,然后调用等号运算符重载,将该临时对象赋值给c1
          c2 = 5.2;
       
         // 调用拷贝构造函数( 有下面两种调用方式) 
          example c5(c2);
          example c4 = c2;  // 注意和 = 运算符重载区分,这里等号左边的对象事先没有创建,故需要调用拷贝构造函数,参数为c2

}

(2)赋值函数:example
&operator=( const example &rhs)。注意,这个类似复制构造函数,将=右边的本类对象的值复制给等号左边的对象,它不属于构造函数,等号左右两边的对象必须已经被创建。若没有显示的写=运算符重载,则系统也会创建一个默认的=运算符重载,只做一些基本的拷贝工作。

example &operator=( const examplw &rhs
)

{
                // 首先检测等号右边的是否就是左边的对象本,若是本对象本身,则直接返回
                if ( this == &rhs )
                {
                        return *this;
                }
                // 复制等号右边的成员到左边的对象中
                this->m_real =
rhs.m_real;
                this->m_imag =
rhs.m_imag;

// 把等号左边的对象再次传出
               // 目的是为了支持连等eg: a=b=c,系统首先运行b=c
               // 然后运行a= ( b=c的返回值,这里应该是复制c值后的b对象)    
                return *this;
          }
         (3)析构函数:~example()。如果没有定义析构函数,编译器会自动生成。其作用是释放一个对象所占的内存(当要删除对象时调用)。它的一个典型应用是在构造函数中用new为一个类中指针型成员开辟独立的动态内存空间,而在析构函数中用delete释放它们。析构函数也只是一个函数,和普通函数没有区别,你想它做什么他就做什么,只是你要告诉他而已。因此析构函数中也可以是一个空函数,只是在合理的时候释放自己分配的内存,如new了一定要delete掉,malloc了一定要free掉,至于你放在哪里随你愿意,不必非要在析构里面,而且放在析构函数里可能会造成不想再使用的内存在程序运行时一直占用(因为只有删除对象时才会调用析构函数)。

七、

关于function & test(){return value;}中函数名前面的&,表示函数的引用返回。引用返回用于当想用函数找到引用应该被绑定在哪一个变量上面时。定义一个变量a,即可调用a = &test();表示变量a的地址与返回值value的地址相同。test()返回值变化引起变量a的值变化。若value为数组名,则写成function * test(){return value;}

所谓引用&就是一个变量的别名,它后面紧跟着就是它要引用的变量名。引用只是一个别名,并不是一种类型,只能看到它所引用数据的地址,所以它与指针符*不同。引用在内存中没有地址,也不占用空间,一旦初始化就不能修改,所以没有指向引用的指针。也就是说引用相当于一个常量指针,指向的地址已固定(但是指向地址中的内容可以改变),不能再用此引用指针指向其它地址。

引用其实是指向某个东西,所以从这点意义上讲是"指针",但是他绝对不是单独存在的,他一定是指示某个已经存在的东西,他一定是某个已经存在的物体的"别名"。而且它如果被初始化赋值给某个变量后,他就始终是这个变量的替身。对引用的改变就是对这个变量的改变。

比如int &a=b;即a的地址就是b的地址,那么b就可以看成是变量a的别名,因为是将a的引用赋给变量b。按我的理解,变量b只关心变量a地址的内容,并不关心变量a本身。只是由于在内存中变量a地址的内容就是变量a本身,所以才将b看成变量a的别名。变量a本身一旦改变,则变量a地址的内容也改变,即b也随之改变。

C++基础知识(一)的更多相关文章

  1. .NET面试题系列[1] - .NET框架基础知识(1)

    很明显,CLS是CTS的一个子集,而且是最小的子集. - 张子阳 .NET框架基础知识(1) 参考资料: http://www.tracefact.net/CLR-and-Framework/DotN ...

  2. RabbitMQ基础知识

    RabbitMQ基础知识 一.背景 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然 ...

  3. Java基础知识(壹)

    写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...

  4. selenium自动化基础知识

    什么是自动化测试? 自动化测试分为:功能自动化和性能自动化 功能自动化即使用计算机通过编码的方式来替代手工测试,完成一些重复性比较高的测试,解放测试人员的测试压力.同时,如果系统有不份模块更改后,只要 ...

  5. [SQL] SQL 基础知识梳理(一)- 数据库与 SQL

    SQL 基础知识梳理(一)- 数据库与 SQL [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5902856.html 目录 What's 数据库 ...

  6. [SQL] SQL 基础知识梳理(二) - 查询基础

    SQL 基础知识梳理(二) - 查询基础 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5904824.html 序 这是<SQL 基础知识梳理( ...

  7. [SQL] SQL 基础知识梳理(三) - 聚合和排序

    SQL 基础知识梳理(三) - 聚合和排序 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5926689.html 序 这是<SQL 基础知识梳理 ...

  8. [SQL] SQL 基础知识梳理(四) - 数据更新

    SQL 基础知识梳理(四) - 数据更新 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5929786.html 序 这是<SQL 基础知识梳理( ...

  9. [SQL] SQL 基础知识梳理(五) - 复杂查询

    SQL 基础知识梳理(五) - 复杂查询 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5939796.html 序 这是<SQL 基础知识梳理( ...

  10. APP测试入门篇之APP基础知识(001)

    前言        最近两月比较多的事情混杂在一起,静不下心来写点东西,月初想发表一遍接口测试的总结,或者APP测试相关的内容,一晃就月底了,总结提炼一时半会也整不完.放几个早年总结内部培训PPT出来 ...

随机推荐

  1. 封装axios方法之一

    一.先来说说为什么要封装axios异步请求. 我们前端开发中总是会遇到跨域的问题,我们会配置proxy来解决跨域的问题,无论是vue 还是react. 如何配置我这里就不说了. 然后...然后我们就会 ...

  2. Java基础—IO小结(二)缓冲流与其它流的使用

    一.缓冲流的使用 每个字节流都有对应的缓冲流: BufferedInputStream / BufferedOutputStream 构造器: 方法摘要与对应节点流类似 使用缓冲流实现文件复制:实际中 ...

  3. 北京Uber优步司机奖励政策(2月19日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  4. MySql慢查询日志——开启/查看/删除

    1,开启慢查询日志 修改mysql.ini文件,加入如下配置: [mysqld] log-slow-queries=H:\mysql_log\slow_query.log long-query-tim ...

  5. element-ui 分页注意事项

    <template> <div id="monitor"> 一页显示 {{currentCount}}条 当前第 {{currentPage}}页 < ...

  6. 创龙DSP6748学习之RS485收发

    1. 先看下原理图,第一个问题,RS485其实就是使用的串口USART1,同时485的输出脚之间接120欧姆的电阻. 遇到个问题,为什么有两个使能引脚?还有RS485_A和RS485_B为什么分别接上 ...

  7. xencenter迁移云主机方法

    问题:POOL中计算节点内存不足. 解决方法:1.为计算节点添加内存(费用高)2.将部分资源迁移到其它POOL中. 方法: 1.选择要迁移的虚拟机 2.选择保存路径 这里可以看到可以批量导出: 注意: ...

  8. Ubuntu 14.04 登录 界面添加 root账号

    1打开终端输入:sudo gedit /usr/share/lightdm/lightdm.conf.d/50-ubuntu.conf 2在弹出的编辑框里加入:greeter-show-manual- ...

  9. apache Subversion 直接支持LDAP域群组

    如果你的Subversion已经用apache的ldap支持用户认证功能,你是否常常在想,既然都用ldap支持认证,为什么不直接支持域群组, 反而在authz文件里面一个一个的手工定义,或者有人用脚本 ...

  10. Java开发工程师(Web方向) - 04.Spring框架 - 第4章.数据访问

    第4章--数据访问 Spring JDBC DAO (Data Access Object) 实现数据访问相关接口(接口和实现分离) ORM (Object Relation Mapping) 对象关 ...