1.在具有指针的类中,必须具有拷贝函数、拷贝赋值函数、析构函数这三种内容,其实现形式如下:
#ifndef _MYSTRING_#define _MYSTRING_#includeclass String{
private:
char* m_data;
public:
String(const char* cstr=0); //default构造函数
String(const String& str); //拷贝构造函数
String& operator=(const String&str); //拷贝赋值函数
~String(); //析构函数
char* get_c_str()const{return m_data;}
};
inline String::String(const char* cstr){
if(cstr){
m_data=new char[strlen(cstr)+1];
strcpy(m_data,cstr);
}
else{
m_data=new char[1];
*m_data='\0';
}
}
inline String::~String(){
delete[]m_data;
}
inline String::String(const String& str){
delete[]m_data;
m_data=new char[strlen(str.m_data)+1];
strcpy(m_data,str.m_data);
}
inline String& String::operator=(const String& str){
if(this==&str)return *this;
delete[]m_data; //self assignment
m_data=new char[strlen(str.m_data)+1];
strcpy(m_data,str.m_data);
return *this;
}
#endif
C++中申请和释放动态内存相对应的操作符为new delete,new先分配内存空间再实施构造函数,delete先实施析构函数再释放内存空间。
self assighment的作用:当左右指针指向同一个内存空间时,若此时没有self assighment
,则会产生不确定行为。
2.全局输出函数构造:
#include<iostream>
ostream& operator<<(ostream& os,const String& str){
os<<str.get_c_str():
return os;}
3.内存空间模式有stack和heap两种。其中stack是存在于某一作用域的一块内存空间,当你调用函数时,就会生成一个stack空间来存放接受的参数及返回地址。heap是由操作系统提供的一块全局内存空间,new操作符申请到的内存空间就是已heap方式分配而来的。
stack内存空间在函数结束时会自动清除,即stack的生命期在作用域结束后自动清除,而heap内存空间在他被delete之前会一直存在,为了避免出现内存泄漏,在函数中由new申请的动态内存要在函数结束时使用delete释放掉。
如想使stack object具有全局的生命期,可以在对象前加上static。
面对字符串申请内存空间时,要申请字符串长度+1的空间。(空字符串要由一个空间来存放结束符号‘\0’)
complex*pc=new complex(1,2);
编译器转化为:
void*element=operator new(sizeof(complex));
pc=static_cast<complex*>(element);
pc->complex::comliex(1,2);
delete pc;
编译器转化为:
complex::~complex(pc);
operator delete(pc);
系统一次从heap中申请到的内存空间必为8n字节
4.array new 需要由array delete来清除
String*p=new String[3];
delete[]p//唤起三次dtor
String* p=new String[3];
delete p;//唤起1次dtor,两份内存没有析构,内存泄露
int*a=new int[3];
delete a;//可行,对象的类型时内置类型或者是无自定义析构函数的类型
5.static 静态函数只能对静态数据进行处理
构造函数在private区的类:singleton
class singleton{
public:
static A& getIn();
setup(){...}
private:
A();
A(const A& a);};
inline A& A::getIn(){
static A a;
return a;}
6.类模板和函数模板
class template:
template<typename T>
class A{
private:
T re,im;friend A& _doapl(A*,const A&);
public:
A(T a=0,T b=0):re(a),im(b){};
A&operator+=(const A&);
T real()const{return re;}
T imag()const{return im;}};
function template
template<typename T>
inline T& min(const T& a,const T& b){
return a<b?a:b}//编译器会对函数进行引数推导,调用相应对象中的重载函数
7.三种类于类的关系
Composition:
template<typename T>
class A{
....
protected:
B<T> b;//底层容器
public:
bool empty()const{return b.empty();}//利用b的操作函数完成
};
A::A(..):B(){..} A的构造函数首先调用B的default构造函数,由内而外
A::~A(...){...~B()} A的析构函数先调用,然后才调用B的析构函数 由外而内
Delegation:Composition by reference
Inheritance:
class A;
class B:public A{.....};
构造由内而外,析构由外而内。
父类与子类同时具有的函数必须为虚函数以便该函数在子类中可以重新构造
virtual function:
class A{ virtual x() const=0;//纯虚
virtual y();//虚}