面向对象技术,多态,重载,静态联编与动态连编,虚函数,抽象类,虚析构函数

来源:互联网 发布:斗鱼tv寅子咋样知乎 编辑:程序博客网 时间:2024/05/20 02:21

多态性
多态性是面向对象程序设计的重要特征之一。它与前面讲过的封装性和继承性构成了面向对象程序设计的三大特征。这三大特征是相互关联的。封装性是基础,继承性是关键,多态性是补充,而多态又必须存在于继承的环境之中。
所谓多态性是指发出同样的消息被不同类型的对象接收时导致完全不同的行为。这里所说的消息主要是指对类的成员函数的调用,而不同的行为是指不同的实现。利用多态性,用户只需发送一般形式的消息,而将所有的实现留给接收消息的对象。对象根据所接收到的消息而做出相应的动作(即操作)。

重载
函数重载 所谓函数重载简单地说就是赋给同一个函数名多个含义。具体地讲,C++中允许在相同的作用域内以相同的名字定义几个不同实现的函数,可以是成员函数,也可以是非成员函数。但是,定义这种重载函数时要求函数的参数或者至少有一个类型不同,或者个数不同。而对于返回值的类型没有要求,可以相同,也可以不同。那种参数个数和类型都相同,仅仅返回值不同的重载函数是非法的。因为编译程序在选择相同名字的重载函数时仅考虑函数表,这就是说要靠函数的参数表中,参数个数或参数类型的差异进行选择。
由此可以看出,重载函数的意义在于它可以用相同的名字访问一组相互关联的函数,由编译程序来进行选择,因而这将有助于解决程序复杂性问题。如:在定义类时,构造函数重载给初始化带来了多种方式,为用户提供更大的灵活性。
运算符重载(1) 运算符重载就是赋予已有的运算符多重含义。C++中通过重新定义运算符,使它能够用于特定类的对象执行特定的功能,这便增强了C++语言的扩充能力。
哪些运算符可以用作重载?
几乎所有的运算符都可用作重载。
具体包含:  
算术运算符:+,-,*,/,%,++,--; 
位操作运算符:&,|,~,^,<<,>>;
逻辑运算符:!,&&,||; 
比较运算符:<,>,>=,<=,==,!=;   
赋值运算符:=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=; 
其他运算符:[],(),->,,(逗号运算符), new, delete,  new[], delete[],->*。
下列运算符不允许重载:., .*, ::, ?:

重载为友元函数(1)运算符重载函数还可以为友元函数。对双目运算符,友元函数有2个参数,对单目运算符,友元函数有一个参数。但是,有些运算符不能重载为友元函数,它们是:=,(),[]和->。
重载为友元函数的运算符重载函数的定义格式如下:
friend <类型说明符> operator <运算符>(<参数表>){……}

静态联编与动态连编
联编是指一个计算机程序自身彼此关联的过程。按照联编所进行的阶段不同,可分为两种不同的联编方法:静态联编和动态联编。
静态联编
静态联编是指联编工作出现在编译连接阶段,这种联编又称早期联编,因为这种联编过程是在程序开始运行之前完成的。
在编译时所进行的这种联编又称静态束定。在编译时就解决了程序中的操作调用与执行该操作代码间的关系,确定这种关系又称为束定,在编译时束定又称静态束定。

动态联编
动态联编实际上是进行动态识别。在上例中,前面分析过了静态联编时,fun()函数中s所引用的对象被束定到Point类上。而在运行时进行动态联编将把s的对象引用束定到Rectangle类上。可见,同一个对象引用s,在不同阶段被束定的类对象将是不同的。那么如何来确定是静态联编还是动态联编呢?C++规定动态联编是在虚函数的支持下实现的。
静态联编和动态联编也都是属于多态性的,它们是不同阶段对不同实现进行不同的选择。上例中,实现上是对fun()函数参数的多态性的选择。该函数的参数是一个类的对象引用,静态联编和动态联编和动态联编实际上是在选择它的静态类型和动态类型。联编是对这个引用的多态性的选择。

虚函数
虚函数是动态联编的基础。虚函数是成员函数,而且是非static的成员函数。说明虚函数的方法如下:
virtual <类型说明符><函数名>(<参数表>) 其中,被关键字virtual说明的函数称为虚函数。

如果某类中的一个成员函数被说明为虚函数,这就意味着该成员函数在派生类中可能有不同的实现。当使用这个成员函数操作指针或引用所标识对象时,对该成员函数调用采取动态联编方式,即在运行时进行关联或束定。
动态联编只能通过指针或引用标识对象来操作虚函数。如果采用一般类型的标识对象来操作虚函数,则将采用静态联编方式调用虚函数。

抽象类
带有纯虚函数的类称为抽象类。抽象类是一种特殊的类,它是为了抽象和设计的目的而建立的,它处于继承层次结构的较上层。抽象类是不能定义对象的,在实际中为了强调一个类是抽象类,可将该类的构造函数说明为保护的访问控制权限。
抽象类的主要作用是将有关的组织在一个继承层次结构中,由它来为它们提供一个公共的根,相关的子类是从这个根派生出来的。
抽象类刻画了一组子类的操作接口的通用语义,这些语义也传给子类。一般而言,抽象类只描述这组子类共同的操作接口,而完整的实现留给子类。
抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类没有重新定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体类了。
#include <iostream.h>//Ex8_15
#include <math.h>
class F
{public:
 virtual double operator()(double x) const=0;
};
class Integral
{ public:
 virtual double operator()(double a,double b,double eps) const=0;
};
class Simpson : public Integral
{ public:
 Simpson(const F& ff) : f(ff){}          //initializing f by ff
 virtual double operator()(double a, double b, double eps) const;
private:
 const F&f;
};
double Simpson::operator ()(double a,double b,double eps) const
{  int done(0);    int n;
   double h,Tn,T2n,In,I2n;
   n=1;  h=b-a;
 Tn=h*(f(a)+f(b))/2.0;                //overloaded operator ()
 In=Tn; 
while(!done)
 {  double temp(0.0);
  for(int k=0;k<=n-1;k++)
  { double x=a+(k+0.5)*h;  temp += f(x); }
  T2n=(Tn+h*temp)/2.0;
  I2n=(4.0*T2n-Tn)/3.0;
  if(fabs(I2n-In)<eps)
                  done=1;
  else
  { Tn=T2n;  n*=2; h/=2; In=I2n;}
 }
 return I2n;
}
class Function : public F
{public:
 virtual double operator()(double x) const
 { return log(1.0+x)/(1.0+x*x); }
};
void main()
  { Function f;
 Simpson simp(f);
 cout<<simp(0,2,1E-10)<<endl;
}

虚析构函数
在析构函数前面加上关键字virtual进行说明,称该析构函数为虚析构函数。例如:
class B{virtual ~B();}...};
该类中的析构函数就是一个虚析构函数。
如果一个基类的析构函数被说明为虚析构函数,则它的派生类中的析构函数也是虚析构函数,不管它是否使用了关键字virtual进行说明。
说明虚析构函数的目的在于在使用delete运算符删除一个对象时,能保析构函数被正确地执行。因为设置虚析构函数后,可以采用动态联编方式选择析构函数。
#include <iostream.h>
class A
{ public:
 virtual ~A(){cout<<"A::~A() called./n";}
};
class B : public A
{ public:
 B(int i){buf=new char[i];}
 virtual ~B()
 { delete[] buf; cout<<"B::~B() called./n";}
private:
 char* buf;
};
void fun(A* a)
{ delete a;}
void main()
{ A* a=new B(15);
 fun(a);
}

#include <iostream.h>
class A
{ public:
  void f()
  {cout<< "A:f()" <<endl;};
};
class B: virtual public A
{ public:
  void f()
    {cout<< "B:f()" <<endl;};
};
class C: public B
{ };
class D: public C, virtual public A
{ public:
  void g();
};
void main()
{ D d;
 d.f();
}

 

原创粉丝点击