首页 > 代码库 > C++学习总结1
C++学习总结1
一、内存管理
一般new 与 delete 同时出现。假如释放一个对象用 delete p即可。多个对象用delet [ ]p
即:new与delete需要搭配好。
C++继承了C的许多函数,malloc 与free就是一个典型例子。
malloc与free是标准库函数。而new与delete是运算符,这个要搞明白。
构造函数 可以理解为初始化函数。 M(void){ }
析构函数可以理解为清除。 ~M(void){}
两者比较:
M *p = new M; //申请动态内存并初始化。
M *p = (M *)malloc(sizeof(M));//申请内存空间
p->init(); //初始化
delete p;//清除并释放内存
p->dest(); //清除
free(p); //释放内存
总结: malloc与free函数不能执行构造函数与析构函数,必须使用成员函数来完成初始化与清除工作。
而 new与delete可以执行构造函数与析构函数。
为何不用new与delete来代替malloc与free?
因为new与delete用在C++里面,在C里面只能用malloc与free。
如何判断内存是否分配成功?
在函数的入口处,用断言: assert(p!=NULL)
内存泄露? 若果没有将分配的内存释放掉,会造成内存的泄露。
在内存不足时,我们一般用return返回,或者exit(1)结束整个程序的运行;
补充一下同步与异步的概念:
同步:就是一件事必须按章来完成,这件事干完了,才能干下一件事情,就像在同步发送数据中,发送方发出数据后,等待接收方响应以后,才可以发送另一个数据包的通讯方式。
异步:就是一件事没干完,我们也可以去做其他的事情,体现了程序的并发执行。在数据发送中,发送方发出数据,不等待接收方响应,接着发送下一个数据包的通讯方式。
二、类与对象
class <类名>
{
public:
private:
protected:
};
Note: 类有逗号 访问操作符: . 或者 -> 或者用域操作符: ::
struct 结构体
{
结构体
} ;
注:两者均有public protected private 三种操作符
而struct成员当中的默认访问权限是共有的,而类中访问权限是私有的。
对象就是类的实例化。
类名 对象名 参数列表
student stu[20];
student xiaozhang;
由事物的生命周期,出来两个概念。构造函数:生命的起始。析构函数:生命的接束。
必须使用与类相同的名称来作为构造函数的名字。参数不管,有参无参都可以。
默认构造函数,当一个类中没有显式的定义任何一个构造函数,那么编译器会自动生成一个不带参数的构造函数。或者当一个类中显式的构造函数没有任何形参,或者全为默认值,则这样的构造函数也是默认构造函数。没有返回值类型。可以有多个。
析构函数的作用:释放掉不在使用的内存。若果函数中没有,我们会自动创建一个析构函数。默认一般函数体为空。
~《类名》();
《类名》::《类名》() 外部定义函数成员。只有一个。无返回值。
友元类,它可以访问类中的私有成员
class myclass
{
语句体;
friend class test;
}
class test
{
public :
int test1(myclass k)
}
友元函数,它可以反问私有成员的 非成员函数。
class myclass
{
语句体;
friend int sub(myclass k);
}
int sub(myclass k)
{
}
三、继承与派生
class 派生类类名 :继承属性 基类名
{
成员定义列表;
} ;
派生类所占的内存空间 = 派生类数据成员所占的内存空间+基类所占的内存空间;
cpoint2(int i,j,p): cpoint(m,n){k=p;}
权限命令 private 》protected》public
基类与继承对象的初始化:
派生类不能够继承基类的构造函数与析构函数,所以,基类成员的构造函数需要通过初始化表来完成。
1、构造函数的执行顺序
先执行基类的构造函数,然后执行派生类中对象成员的构造函数,最后执行派生类自身的构造函数。
2、析构函数与构造函数顺序相反。
注:C++不是完全的面向对象,其初始化可以用构造函数来完成。比如:student stu(100,200) 相当于 student stu =
new student( 100,200); 省略了 。。。= new sudent。。。
多重继承 class C :public A,public B
四、函数
我们对函数名进行声明的同时,可以与函数定义时的与函数的类型函数名与参数类型保持一致,可以形参名省略,或者不写。
函数类型名 函数名(形参)
{
函数体;
}
值的传递方式:按地址传递与按值传递。其中,按地址传递又有一种方式,按引用传递。
void acc(int *p,int k)
void acc(int *&p,int &k) 此时的p不是指针型。int n;func(&n)
引用与指针?
C++中指针能实现的功能,大部分引用也可以实现。但是,有一小部分是无法替代的。
第一,如果对象为空。则只能用指针。因为没有空引用
第二,如果程序先指向了一个对象,然后再指向其他对象,这个时候也必须用指针,因为引用是一个常量,是不能对其进行重新赋值的。
函数的返回值,return or else
局部变量与全局变量。
静态局部变量 static int c = 0;
静态全局变量存在于源文档中,不易发生错误。
外部变量:写一些大的程序时,需要涉及多个源程序文档,这时,程序文件中的全局变量的作用域可以扩大到其他文件中,也就是说,一个文件中的全局变量,也可以在另一个文件中使用,那么这个全局变量就叫做另一个文件的外部变量。
extern double a;
f1.cpp
double a;
f2.cpp
extern double a;
注:不能初始化变量,只能说明变量在其他地方定义过。
对应静态全局变量,不能用extern 在其他文件中使用。
函数的调用:
#include<iostream>
using namespace std;
void show(int data[5] );
int main()
{
int k[5];
for(int i=0;i<5;i++)
{
k[i]=i;
}
show(k);//传递的是数组元素的地址
return 0;
}
void show(int data[5])
{
for(int i=0;i<5;i++)
cout<<data[i]<<endl;
}
void show (int data[])
void show( int *data) //data可以为数组,也可以为一个元素
内联函数:
可以避免函数调用的开销,inline void swap(int a ,int b);
函数重载:
返回值相同,名字相同,函数特征不同的函数。
int show(const age)
int show (age)
复制形参的时候并不需要考虑形参是否为const类型。
函数的嵌套与递归:
递归必须有一个终止条件。
main 函数:
int main(int argc,int *argv[ ]);
五、异常处理
参考文章:http://blog.chinaunix.net/uid-21411227-id-1826957.html C++异常处理机制
try语句,发现问题。主要是为了圈定异常发生的具体位置,即哪些语句发生了异常。
一般格式:
try
{
//内嵌了throw语句的语句。
}
try语句用来包围可能出现问题的代码区域,其中可能有一个或一个以上throw语句。如果没有包含任何throw语句,程序会根据运行的情况抛出预设的默认的错误。
catch语句,分析解决问题。主要用来定义异常处理。将出现异常后的处理语句放在catch块中,这样可以使得当异常抛出以后,进行类型的配置。从而捕获异常。
一般格式:
catch (type [exception])
{
//匹配throw抛出的exception的语句块
}
catch()
{
//匹配throw抛出的任意类型的语句块
}
catch语句块中圆括号包含的参数只能是一个
throw语句块 ------ 得出结论
throw语句块,抛出程序的异常。一旦发生异常则抛出异常。
一般格式:
throw type exception;
throw;
六、模板
参考资料: http://blog.csdn.net/qinbaby/article/details/6735920 笨鸟先飞之C++模板编程
模板就是一种使用无类型参数来产生一系列函数的或者类的机制。
他的出现可以使用户为类或者函数声明一种一般模式,从而使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
返回两个值当中的最大者。
template 《class type 》 type max (type a,type b)
{
}
这个与函数的重载与带参数的宏定义有关。
程序员只需提供一个函数模板的描述即可。编译器会自动生成若干具体函数代码来复制函数模板中类参的具体化。
C++ 主要由类与函数组成。
下面主要有类模板与函数模板组成。
1、函数模板
注:函数的形参表不能为空。typename 与class 可以互换。主要是为了兼容。
模板的使用:当模板的类型参数不止一个的时候,需要在每个参数前面都要加上关键字typename或者class。
函数模板的小例子:
template <typename type >type max(type a,type b)
{
if(a>b)
return a;
else
return b;
}
调用时,直接用 max(n,m)
模板函数指的是函数模板的一种实例化,具体化。具有程序代码。
通用函数模板:
template <typename type>
int max(const type &a , const type &b)
{
}
特殊化的通用模板:
template < >
int max (const char * const &a, const char * const &b)
{
}
现在当调用max函数的时候,如果传过来的是两个字符指针,编译器将会调用特殊化的函数模板,如果传递过来的是其他参数,则调用通用函数模板。
const char *p1 = “love”;*p2=“c++”
double m,n;
max(p1,p2)//调用特殊化的函数模板
max(m,n)//调用通用的函数模板
2、类模板
template <typename type1,typename type2,typename typeN>
class 类名
{
//类的定义
} ;
注:template开头,typename可以用class代替,模板的参数个数可以为一个或者多个。但必须是抽象化的结果。
template <typename type> //类模板的声明
class save
{
type a;
type b;
public :
save(type num1,type num2) //类成员函数
{
a = num1;
b = num2;
}
};
模板类 是一种具体的、实实在在的函数的定义。
类模板的特殊化:
template <> //类模板的声明
class save
{
type a;
type b;
public :
save(int num1,int num2) //类成员函数
{
a = num1;
b = num2;
}
};
方便了代码的重复使用。
实例如下:
// Cplusplus.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
//函数模板的重载
template <typename T>
T const& Max (T const &a, T const &b)
{
return a < b ? b : a;
}
template <typename T>
T const& Max(T *const &a, T *const &b)
{
return *a < *b ? *b :*a;
}
//函数模板的特例化,此时函数退化为普遍函数,优先匹配
const char * Max(const char* &a, const char* &b)
{
return strcmp(a,b) < 0 ? a : b;
}
//函数模板,编译时根据模板函数传递的实参类型生成具体的函数,形参与实参必须严格匹配
template <typename T>
void swap1(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
};
// 类模板
template <typename T>
struct Node
{
Node(T data)
{
m_Data = http://www.mamicode.com/data;
m_pPrev = m_pNext = NULL;
}
T m_Data; //通用类型的数据元素
Node<T> *m_pPrev;//指向上一个元素的指针
Node<T> *m_pNext;//指向下一个元素的指针
};
template<typename T>
class CDList
{
private:
int m_nMessage;
int m_nCount;
Node<T>* m_pHead;
Node<T>* m_pTail;
public:
CDList();
virtual ~CDList();
public:
int GetLen() const
{
return m_nCount;
}
Node<T>* GetHead() const
{
return m_pHead;
}
Node<T>* GetTail() const
{
return m_pTail;
}
public:
bool Change(int nIndex1,int nIndex2);
void Release();
//增加
Node<T>* AddTail(T Data);
Node<T>* AddHead(T Data);
Node<T>* operator[](int nIndex);
//删除
bool DeleteNode(int nIndex);
void PrintAll();
//查找
Node<T>* FindNode(int nIndex);
};
int _tmain(int argc, _TCHAR* argv[])
{
int nNum1 = 400;
int nNum2 = 300;
cout << nNum1 << "," << nNum2 << endl;
swap1<int>(nNum1,nNum2); // 前面这一部分 swap<int> 为实例化为int类型的模板函数再调用
cout << nNum1 << "," << nNum2 << endl;
return 0;
}
七、容器
参考资料:http://blog.csdn.net/acosoft/article/details/4395468 浅谈C++容器(一)
容器就像一个器皿一样,用来存放某些给定类型对象的模板类型。简单理解为容器是保存其他对象的对象。当然,还包含一系列处理其他对象的方法。
主要分为: 顺序容器、关联类容器和容器适配器。
关联类通过键 key来存储和读取元素。而顺序容器则是通过元素在容器中的位置顺序地存储和访问元素。
顺序容器:
顺序容器:vector、list、deque
关联容器:set 、 multiset、 map、 multimap
容器适配器:stack、queue、priority_queue
其中,顺序容器是一种各元素之间有顺序关系的线性表,是一种线性结构的可序群集。
关联式容器是非线性结构的树结构,更准确的讲是二叉树结构。它的一个显著特点是,可以保存两种数据,键和值。而顺序容器只能保存一种,要么关键字,要么是值。
容器适配器是一种容器的容器,我们可以理解为容器的接口。
和其他语言不一样的是,C++中处理容器是采用的基于模板的方式,这些数据结构可以与算法相结合。
vector 线性顺序结构,相当于数组,大小可以指定,也可以不指定,支持自动扩展。我们可以把它看做成动态数组。
list 线性链表结构,双向链表,由若干结点构成,每一个结点包含一个信息块,一个前驱指针一个后驱指针。
STL中只有vector和map可以通过类数组的方式操作元素
ANSIC:是标准C定义,它是由美国国家标准化协会制定,目前绝大多数的编译器和IDE都支持,至少是包含支持ANSIC。
Turbo C/C++:既是编译器,也是IDE。是Borland公司的产品。
Borland C++:既是编译器,也是IDE。是Borland公司的产品。
VC/VC++:既是编译器,也是IDE。是微软公司的产品。
gcc :GNU的C/C++编译器
g++:GNU的C/C++编译器
Dev C++:纯粹的IDE,使用gcc,g++编译器。仅支持标准C/C++。