5.malloc与free是C++/C的标准库函数,而new/delete是C++的运算符。
对于非内部数据结构的对象而言,只用malloc/free无法满足动态对象的要求。
malloc和free是库函数而不是运算符,不在编译器控制权限之内,不能够执行构造函数和析构函数。
6.智能指针auto_ptr是安全指针,包含在空间std中,用它构造的对象,析构函数总在退栈过程中被调用。
auto_ptr
auto_ptr
7.vector*a1=newvector();
a1->push_back(d1);//浅拷贝
deletea1;//释放vector对象,vector包含的元素也同时释放了
8.静态模板类:
template
template用法
STL
9.一个空类默认产生的成员函数:
默认构造函数、析构函数、拷贝构造函数、赋值函数。
拷贝构造函数:
CExample(const CExample&C)就是我们自定义的拷贝构造函数。
可见,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型,不可变的。
例如:
类X的拷贝构造函数的形式为X(X&x)。
当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。
也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。
以下情况都会调用拷贝构造函数:
一个对象以值传递的方式传入函数体
一个对象以值传递的方式从函数返回
一个对象需要通过另外一个对象进行初始化。
深拷贝和浅拷贝可以简单理解为:
如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
CA(constCA&C)
{
a=C.a;
str=newchar[a];//深拷贝
if(str!
=0)
strcpy(str,C.str);
}
10.class和struct的区别:
class中变量默认是private,struct中变量默认是public。
C++中存在struct是为了兼容以前的C项目。
11.类中,初始化列表的初始化顺序是根据成员变量的声明顺序来执行的。
常量必须在构造函数的初始化列表里初始化或者将其设置成static。
classA
{
A(){constintSize=0;}
};
或者
classA
{
staticconstintSize=0;
};
12.MFC中Cobject的析构函数是虚拟的。
原因:
多态的情况,CBase*p=newCChild();析构时,如果不是virtual则会调用父类的析构函数,而实际new的子类的空间可能不会完全释放;而如果是virtual的析构函数,则会调用虚拟指针执行的子类的析构函数来释放空间。
13.strcpy,strncpy,strlcpy
strcpy是依据/0作为结束判断的,如果to的空间不够,则会引起bufferoverflow。
strcpy(char*to,constchar*from)
{
char*save=to;
for(;(*to=*from)!
='/0';++from,++to);
return(save);
}
strncpy(path,src,sizeof(path)-1);//要赋值的长度
path[sizeof(path)-1]='/0';
len=strlen(path);
strlcpy(char*dst,constchar*src,size_tsize);
而使用strlcpy,就不需要我们去手动负责/0了,仅需要把sizeof(dst)告之strlcpy即可:
strlcpy(path,src,sizeof(path));
len=strlen(path);
if(len>=sizeof(path))
printf("srcistruncated.");
并且strlcpy传回的是strlen(str),因此我们也很方便的可以判断数据是否被截断。
2012.07.24
1.String类P112
classString
{
public:
String(constchar*str=NULL);//普通构造函数
String(constString©);//拷贝构造函数
~String();
String&operator=(constString&other);//赋值函数
private:
char*m_data;
};
String:
:
String(constchar*str/*=NULL*/)
{
if(NULL==str)
{
m_data=newchar[1];
m_data='\0';
}
else
{
intlength=strlen(str);
m_data=newchar[length+1];
strcpy(m_data,str);
}
}
String:
:
~String()
{
delete[]m_data;
}
String:
:
String(constString©)
{
intlength=strlen(copy.m_data);
m_data=newchar[length+1];
strcpy(m_data,copy.m_data);
}
String&String:
:
operator=(constString&other)
{
if(this==&other)
{
return*this;
}
delete[]m_data;
m_data=newchar[strlen(other.m_data)+1];
strcpy(m_data,other.m_data);
return*this;
}
调用:
Strings1("hello");
Strings2=s1;或者Strings2(s1);//拷贝构造函数
Strings3;s3=s2;//赋值函数
2.重载在编译期间就确定了,是静态的,重载和多态无关。
真正与多态相关的是覆盖(虚函数)。
当定义了父类的虚函数后,父类指针根据赋给它的不同的子类的指针,动态地调用属于子类的该函数,这样的函数调用在编译期间是无法确定的,调用子类的虚函数的地址无法给出。
封装可以隐藏细节,使得代码模块化,继承可以扩展存在的代码模块,它们都是为了代码重用。
而多态是为了接口重用。
override—覆盖(派生类函数覆盖基类virtual函数),
overload—重载(语义、功能相似的几个函数用同一个名字表示,但参数或返回值不同),
overwrite—重写(派生类的函数屏蔽了与其同名的基类函数)。
重写:
(1)如果派生类的函数与基类的函数同名,但是参数不同。
此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。
此时,基类的函数被隐藏(注意别与覆盖混淆)。
classParent
{
public:
voidF()
{
cout<<"ParentF().\n";
}
virtualvoidG()
{
cout<<"ParentG().\n";
}
intAdd(intx,inty)
{
returnx+y;
}
floatAdd(floatx,floaty)//overload
{
returnx+y;
}
};
classChild:
publicParent
{
voidF()//overwrite
{
cout<<"ChildF().\n";
}
virtualvoidG()//override
{
cout<<"ChildG().\n";
}
};
Child*child;
Parent*p=(Parent*)child;(或者Parent*p1=newChild;p1->G();)
p->F();//ParentF().
p->G();//ChildG().
3.voidfunction()const;//常成员函数,它不改变对象的成员变量.也不能调用类中任何非const成员函数。
4.析构函数可以是private的。
classTest1
{
public:
Test1()
{
cout<<"Constructor."<};
voidDeleteTest1()
{
cout<<"Deletetest1."<deletethis;
}
private:
~Test1()
{
cout<<"Destructor."<}
};
Test1*t1=newTest1();
//deletet1;编译的时候会报错,因为析构函数时private的,delete调用不到它
t1->DeleteTest1();
5.构造函数不能是virtual的。
构造函数可以是private的,但是该类不能被实例化,因为不能执行初始化。
private的构造函数不会生成默认的拷贝构造函数。
6.构造函数是从最初始的基类开始构造,各个类的同名变量没有形成覆盖,都是单独的变量。
接口的调用是就近的,优先调用离自己最近的接口(从当前层往上向父辈、祖父辈)。
7.A*pa=newA();
B*pb=(B*)pa;//始终是A类空间
deletepa,pb;//删除所指向的地址,但pa、pb指针并没有删除,也就是悬浮指针
pa=newB();//B类的空间
pb=(B*)pa;
8.子类继承父类时,不管什么继承方式,子类都会继承父类的任何数据成员和方法,不管数据成员和方法是什么类型,只是因为继承方式或类型的原因而