c++primer plus第十三章-抽象基类、纯虚函数及本章总结

c++primer plus第十三章-抽象基类、纯虚函数及本章总结

1)private和protected之间的区别只有在基类派生的类中才会表现出来。派生类的成员可以直接访问基类的保护成员,但是不能直接访问基类的私有成员。因此,对于外部世界来说,保护成员的行为与私有成员相似;但是对于派生类来说,保护成员的行为与公有成员相似。


2)纯虚函数:c++通过使用纯虚函数提供未实现的函数。纯虚函数声明的结尾处为=0。

class BaseEllipse

{

private:

public:

virtual double Area() const =0 ;//仍然可以定义

}


3)当声明中包含纯虚函数时,则不能创建该类的对象。包含纯虚函数的类只用作基类,要成为真正的ABC(抽象基类),必须至少包含一个纯虚函数。原型中的=0使虚函数成为纯虚函数。

ABC描述的是至少使用一个纯虚函数的接口,从ABC派生出的类将根据派生类的具体特征,使用常规虚函数来实现这种接口。


4)默认构造函数:默认构造函数要么没有参数,要么所有的参数都有默认值。如果没有定义任何构造函数,编译器将定义构造函数,让你能够创建对象。

第一:自动生成的默认构造函数的另一项功能是,调用基类的默认构造函数以及调用本身是对象的成员所属类的默认构造函数。

第二:如果派生类构造函数的成员初始化列表中没有显式调用基类构造函数,则编译器将使用基类的默认构造函数来构造派生类对象的基类部分。

第三:提供构造函数的动机之一是确保对象总能被真确地初始化。如果类包含指针成员,则必须初始化这些成员。最好提供一个显式默认构造函数,将所有的类数据成员都初始化为合理的值。


5)在下述情况下,将使用复制构造函数:

第一:将新对象初始化为一个同类对象;

第二:按值将对象传递给函数;

第三:函数按值返回对象;

第四:编译器生成临时对象。

如果程序没有使用(显式或隐式)复制构造函数,编译器将提供原型,但是不提供函数定义;否则,程序将定义一个执行成员初始化的复制构造函数。新对象的每个成员都被初始化为原始对象相应成员的值。如果成员为类对象,则初始化该成员时,将使用相应类的复制构造函数。


6)赋值运算符

默认的赋值运算符用于处理同类之间的赋值。不要将赋值与初始化混淆了。如果语句创建新的对象,则使用初始化,如果语句修改已有对象的值,则是赋值。

Star sirius;

Star alpha = sirius; //初始化

Star dogstar;

dogstar = sirius;//赋值


7)默认赋值为成员赋值。如果成员为类对象,则默认成员赋值将使用相应类的赋值运算符。如果需要显式定义复制构造函数,则基于相同的原因,也需要显式定义赋值运算符。Star类的赋值运算符的原型如下:

Star & Star :: operator = (const Star &);

赋值运算符函数返回一个Star对象引用。


8)编译器不会生成将一种类型赋给另一种类型的赋值运算符。如果希望能够将字符串赋给Star对象,则方法之一:

Star & Star :: operator =(const char *){... ...}

方法之二:使用转换函数:

将字符串转换为Star对象,然后使用将Star赋给Star的赋值函数。


9)一定要定义显式析构函数来释放类构造函数使用new分配的所有内存,并完成类对象所需的任何特殊的清理工作。对于基类,即使它不需要析构函数,也应提供一个虚析构函数。


10)编写使用对象作为参数的函数时,应按引用而不是按值来传递对象。这样做的原因之一是为了提供效率。按值传递对象涉及到生成临时拷贝,即调用复制构造函数,然后调用析构函数。调用这些函数需要时间,复制大型对象比传递引用花费的时间要多很多。如果函数不修改对象,应将参数声明为const引用。

按引用传递对象的另一个原因是,在继承使用虚函数时,被定义为接受基类引用参数的函数可以接受派生类。


11)返回对象和返回对象的引用:应该返回引用而不是返回对象的原因在于,返回对象涉及生成返回对象的临时副本,返回对象的时间成本包括调用复制构造函数生成副本所需的时间和调用析构函数删除副本所需的时间。返回引用可以节省时间和内存。直接返回引用与按引用传递对象相似。


12)但是,并不总是可以返回引用。函数不能返回在函数中创建的临时对象的引用。因为当函数结束时,临时对象消失,因此这种引用将是非法的。这个时候,应该返回对象,以生成一个调用程序可以使用的副本。

通用的规则是,如果函数返回在函数中创建的临时对象,则不要使用引用。

Vector Vector :: operator+(const Vector & b) const

{

return Vector(x + b.x, y+ b.y);//返回的是对象

}

如果函数返回的是通过引用或指针传递给它的对象,则应按引用返回对象。

const Stock & Stock :: topval(const Stock & s) const

{

if(s.total.val > total_val)

return s;

else

return *this;//返回指针或引用

}


13)如果派生类不是一种特殊的类,则不要使用公有派生。在某些情况下,最好的方法就是创建包含纯虚函数的抽象数据类,并从它派生出其他的类。

无需进行显式类型转换,基类指针就可以指向派生类对象,基类引用可以引用派生类对象。另外,反过来是不行的。即不能在不进行显式转换的情况下,将派生类指针或引用指向基类对象。这种显式类型转换(向下强制转换)可能有意义,也可能没有意义,取决于类声明。


14)如果编译器发现程序将一个对象赋给同一个类的另一个对象,它将自动为这个类提供一个赋值运算符。这个运算符的默认或隐式版本将采用成员赋值,即将原对象的相应成员赋给目标对象的每个成员。如果对象属于派生类,编译器将使用基类赋值运算符来处理派生类对象中基类部分的赋值。如果显式地为基类提供了赋值运算符,将使用该运算符。


15)如果类构造函数使用new来初始化指针,则需要提供一个显式赋值运算符。因为对于派生类对象的基类部分,c++将使用基类的赋值运算符,所以不需要为派生类重新定义赋值运算符,除非它添加了需要特别留意的数据成员。

Brass blips;

BrassPlus snips(... ...);

blips = snips;//使用哪个赋值运算符呢??

blips.operator=(snips);

可以将派生类对象赋给基类对象。

Brass gp(... ...);

BrassPlus temp;

temp = gp;//???

temp.operator=(gp);//不可行

派生类引用不能自动引用基类对象,除非有转换函数:

BrassPlus(const Brass &);


16)有关使用基类方法的说明:以公有方法派生的类对象可以通过多种方式来使用基类的方法:

第一:派生类对象自动使用集成而来的基类方法,如果派生类没有重新定义方法。

第二:派生类的构造函数自动调用基类的构造函数。

第三:派生类的构造函数自动调用基类的默认构造函数,如果没有在成员初始化列表中指定其他构造函数。

第四:派生类构造函数显式地调用成员初始化列表中指定的基类构造函数。

第五:派生类方法可以使用作用域解析运算符来调用公有的和受保护的基类方法。

第六:派生类的友元函数可以通过强制类型转换,将派生类引用或指针转换为基类引用或指针,然后使用该引用或指针来调用基类的友元函数。


你可能感兴趣的:(C++,C语言)