函数重载
适用情况:
- 没有合理的默认值
- 需要不同的算法
- 需要在参量表中支持各种类型
复制构造函数
XXX(const XXX& xxx);
浅拷贝:成员变量复制,即两个对象的成员变量指向同一内存。
深拷贝:成员变量内存复制,即指向值相同的不同的内存。
规则:尽量使用深拷贝,防止栈中的对象销毁,导致内存数据出错。
运算符重载
XXX operator++();
返回对象:
XXX xxx; return xxx; | //返回显式命名的对象,返回时函数会进行对象拷贝 |
return XXX(...); | //返回无名的临时对象,返回时函数会进行对象拷贝 |
const XXX& operator++(); return *this; | //返回对本对象的引用,防止对象创建与拷贝 |
const XXX opeator ++(int x); | //后置单目运算符 //注:单目运算符一般不带参数,但后置的++和--除外,使用int x作为标志。 |
XXX operator +(const XXX & xxx); | //+运算符重载 |
XXX& operator =(const XXX & xxx); | //=赋值运算符重载 //注:防止自己对自己赋值,if(this == &xxx) return *this; |
operator unsigned short(); {return intx;} | //转换运算符,采用构造函数将值转为对象, //注:调用 int x = xxx;对象转为值 |
继承
构造:先父类后子类
析构:先子类后父类
方法重载:同一个类中与相同的函数名,但是不同的参数列表或返回类型
方法覆盖:子类与父类的函数有完全相同的定义(函数名、参数列表、const关键字、返回类型)
方法隐藏:子类覆盖父类中重载的某一个方法,或者定义同名的方法,会隐藏父类所有同名方法(如需覆盖,需对父类中所有的重载方法进行覆盖),破坏多态性。此时调用父类方法需显式调用: childObj.fatherClass::method();
虚函数 virtual(覆盖)
构造子类对象时,父类部分和子类部分是连续存储的。许多编译器采用v表(虚函数表)记录对象与虚函数的关系,该表存储了每个类中的虚函数,每个类的对象均有一个指向该表的虚表指针(vptr或v-poiter),故构造子类对象的父类部分时,vptr就初始化为指向v表的正确部分(父类虚函数),构造子类部分时,vptr重新指向子类对象内的虚函数的覆盖部分。
所以虚函数的对象需对v表进行维护,创建v表会造成系统开销,但之后创建虚函数,系统开销就很小了。
规则:需要派生时,必须使用虚函数,析构函数也为虚函数。
虚函数 数据切片slicing
注:虚函数只对引用和指针有效,按值传递对象不允许调用虚函数。
数据切片:在调用函数进行对象值传递时,函数希望类型为FatherClass,编译器会把ChildClass切片,只保留FatherClass部分,即使调用虚函数,也是FatherClass的虚函数。
FatherClass*father = new ChildClass;
voidmethod(FatherClass father)
{
father.dowork();//dowork是虚函数,运行结果为父类虚函数的执行结果
}
虚函数 析构函数
规则:类中含有虚函数,则析构函数也应该是虚函数。
FatherClass*child= new ChildClass;
delete child;
即:如果FatherClass 的析构函数为虚函数,则delete child时,会调用ChildClass的析构函数,子类的析构函数会主动调用父类的析构函数,所有会正常释放对象。反之,如果FatherClass的析构函数不是虚函数,则delete child时,会调用FatherClass的析构函数,childClass部分不会释放。
虚函数 构造函数
注:构造函数不能是虚函数
新父类指针,指向已有子类对象的拷贝:Clone()
classFatherClass{
virtual FatherClass * Clone(){
return new FatherClass(*this);//需有拷贝构造函数
}
}
classChildClass : public FatherClass{
virtual FatherClass * Clone(){
return new ChildClass(*this);
}
}
FatherClass*father = child.Clone();//复制子类对象