面向对象往年卷复习

  • C++程序中,任何类都有默认的构造函数。错(当定义了构造函数就没有默认的构造函数,或者定义一个所有参数都带初始值的构造函数,他也为默认的构造函数,两者不能同时出现)
  • 某函数的形参为引用型形参,则该引用的生命周期为函数调 用时存在,函数返回后不存在。(函数引用返回要注意对象生命期)
    • 不能返回局部变量的引用。如上面的例子,如果temp是局部变量,那么它会在函数返回后被销毁,此时对temp的引用就会成为“无所指”的引用,程序会进入未知状态。

      不能返回函数内部通过new分配的内存的引用。虽然不存在局部变量的被动销毁问题,但如果被返回的函数的引用只是作为一个临时变量出现,而没有将其赋值给一个实际的变量,那么就可能造成这个引用所指向的空间(有new分配)无法释放的情况(由于没有具体的变量名,故无法用delete手动释放该内存),从而造成内存泄漏。因此应当避免这种情况的发生

      当返回类成员的引用时,最好是const引用。这样可以避免在无意的情况下破坏该类的成员。

      可以用函数返回的引用作为赋值表达式中的左值

  • 动态联编静态联编
    • 静态联编是指联编工作在编译阶段完成的,这种联编过程是在程序运行之前完成的,又称为早期联编。要实现静态联编,在编译阶段就必须确定程序中的操作调用(如函数调用)与执行该操作代码间的关系,确定这种关系称为束定,在编译时的束定称为静态束定。静态联编对函数的选择是基于指向对象的指针或者引用的类型。其优点是效率高,但灵活性差。
//例1:静态联编

#include"iostream.h"

class A

{public:

 voidf(){cout<<"A"<<"";}

};

classB:publicA

{public:

 voidf(){cout<<"B"<<endl;}

};

Void main()

{A*pa=NULL;

Aa;Bb;

pa=&a;pa->f();

pa=&b;pa->f();

}
该程序的运行结果为:A   A
    • 动态联编是指联编在程序运行时动态地进行,根据当时的情况来确定调用哪个同名函数,实际上是在运行时虚函数的实现。这种联编又称为晚期联编,或动态束定。动态联编对成员函数的选择是基于对象的类型,针对不同的对象类型将做出不同的编译结果。C++中一般情况下的联编是静态联编,但是当涉及到多态性和虚函数时应该使用动态联编。动态联编的优点是灵活性强,但效率低。

      动态联编规定,只能通过指向基类的指针或基类对象的引用来调用虚函数,其格式为:指向基类的指针变量名->虚函数名(实参表)或基类对象的引用名.虚函数名(实参表)

      实现动态联编需要同时满足以下三个条件:

      ①    必须把动态联编的行为定义为类的虚函数。

      ②    类之间应满足子类型关系,通常表现为一个类从另一个类公有派生而来。

      ③    必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数。

例2:动态联编

#include"iostream.h"

classA

{public:

Virtual voidf()//虚函数

{cout<<"A"<<"";}};

classB:publicA

{public:

Virtual voidf()//虚函数

{cout<<"B"<<endl;}

};

voidmain()

{ A*pa=NULL;

Aa;Bb;

pa=&a;

pa->f();

pa=&b;

pa->f();

}

该程序的运行结果为:A  B
    • 动态联编要求派生类中的虚函数与基类中对应的虚函数具有相同的名称、相同的参数个数和相同的对应参数类型、返回值或者相同,或者都返回指针或引用,并且派生类虚函数所返回的指针或引用的基类型是基类中虚函数所返回的指针或引用的基类型的子类型。如果不满足这些条件,派生类中的虚函数将丢失其虚特性,在调用时进行静态联编。
例3:通过指向基类的指针来调用虚函数

#include"iostream.h"

Class base

{

public:

virtual void fun1(){cout<<"base fun1"<<endl;}

virtual void fun2(){cout<<"base fun2"<<endl;}

void fun3(){cout<<"base fun3"<<endl;}

void fun4(){cout<<"base fun4"<<endl;}

};

Class derived:public base

{public:

Virtual void fun1(){cout<<"derived fun1"<<endl;}

Virtual void fun2(intx){cout<<"derived fun2"<<endl;}

Virtual void fun3(){cout<<"derived fun3"<<endl;}

Void fun4(){cout<<"derived fun4"<<endl;}};

Void main()

{base*pb;

derivedd;

pb=&d;//通过指向基类的指针来调用虚函数pb->fun1();pb->fun2();pb->fun3();pb->fun4();}

该程序的运行结果:

Derived fun1 base fun2 base fun3 base fun4

本例中函数fun1在基类base和派生类derived中均使用了关键字virtual定义为虚函数,并且这两个虚函数具有相同的参数个数、参数类型和返回值类型。因此,当指针pb访问fun1函数时,采用的是动态联编。函数fun2在基类base和派生类de-rived中定义为虚函数,但这两个虚函数具有不同的参数个数。函数fun2丢失了其虚特性,在调用时进行静态联编。函数fun3在基类base中说明为一般函数,在派生类derived中定义为虚函数。在这种情况下,应该以基类中说明的成员函数的特性为标准,即函数fun3是一般成员函数,在调用时采用静态联编。函数fun4在基类base和派生类derived中均说明为一般函数,因此基类指针pb只能访问base中的成员。

  • 常对象只能调用常成员函数
    • 否则函数体内部可能会出现修改该常量的语句,如果常对象调用非常量成员函数编译器会报错

 

posted @ 2020-11-24 19:10  rippleD  阅读(13)  评论(0)    收藏  举报