分类: C/C++
2013-02-22 15:08:27
1.C++中三个概念
函数重载:
在C++程序中,可以将语义、功能相似的几个函数用同一个名字表示,即函数重载。
重载的实现:
几个同名的重载函数仍然是不同的函数,它们是如何区分的呢?我们自然想到函数
接口的两个要素:参数与返回值。如果同名函数的参数不同(包括类型、顺序不同),那么容易区别出它们是不同的函数。
重载与覆盖
成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。
隐藏规则:
本来仅仅区别重载与覆盖并不算困难,但是C++的隐藏规则使问题复杂性增加了许多。
这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual
关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual
关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
另一观点
如果基类有某个函数的多个重载(overload)版本,而你在子类中重写(overwrite)了其中的一个,或是子类添加新的函数版本,则所有基类的重载版本都被遮蔽。所以,正常情况下,在子类中应重写基类中的所有重载版本。
具体地讲,继承类中的重载和重写都包含了重写的涵义,即只要函数名一样,基类的函数版本就会被遮蔽,所以,在派生类中要保持基类的重载版本,就应该重写所有基类的重载版本。重载只在当当前类中有效,继承会失去重载的特性。也就是说,把基类的重载函数放在继承类里,就必须重写。
======
1,重写,必然发生在基类和派生类中,其类函数用virtual修饰,派生类用override修饰
2,隐藏,在子类中写一个和基类一样名字(参数不同也算)的非虚函数,会让基类中的函数被隐藏,这时候一般编 译时会报一个警,子类中的函数用new修饰一下就不报警了
3,重载,必然发生在一个类中,函数名相同,参数类型或者顺序不同构成重载,与返回类型无关
========
重载:同一个作用域内发生(比如一个类里面),定义一系列同名方法,但是方法的参数列表不同。这样才能通过传递不同的参数来决定到底调用哪一个。而返回值类型不同是不能构成重载的。
重写:继承时发生,在子类中重新定义父类中的方法,子类中的方法和父类的方法是一样的
例如:基类方法声明为virtual(虚方法),派生类中使用override申明此方法的重写.
隐藏:基类方法不做申明(默认为非虚方法),在派生类中使用new声明此方法的隐藏。
重载时,根据参数选择调用的方法;
重写时,访问父类子类皆调用子类的重写方法;
隐藏时,访问父类则调用父类的方法,子类子类的方法。
补充:重写override一般用于接口实现和继承类的方法改写,要注意
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖
=====
举个最简单的例子:
有一个People父类,他有一个GuoJI()方法,默认情况下他显示是一个中国人,而有一个American子类继承People父类,在继承GuoJi()这个方法就有点不合逻辑了,所以他就需要重写这个方法:
Class People
{
public virtual void GuoJi()
{
Console.WriteLine("大家好,我来自中国!");
}
}
Class American:People
{
public override void GuoJi()
{
Console.WriteLine("大家好,我来自美国!");
}
}
这样的话在主函数的入口处:
People p1=new People();
p1.GuoJi();
People p2=new American();
p2.GuoJi();//调用父类中有的虚方法(实质在子类中对这一方法进行了重写)
Console.Readkey();
运行后的显示结果是:
大家好,我来自中国!
大家好,我来自美国!
隐藏(new关键字):
上面方法重写中,当不能把基类中的方法声明为Virtual时,可以用另一种方法来实现上面例子中的功能,那就是在派生类中声明方法时使用new关键字,从而有效的隐藏基类中的同一名字的方法(次方法与参数无关)。
这种方式不叫重写,子类跟父类中的同名方法因为new这一关键字的关系而没有半毛钱的联系,所以子类可以调用自己类中的这一方法而不会被基类中的同名方法所干扰。
(需要注意的是,new关键字不可以用在抽象类中,因为抽象类中的抽象方法必须重写)
还是上面的那个例子,我们来看一下用new的实现方法:
Class People
{
public void GuoJi()
{
Console.WriteLine("大家好,我来自中国!");
}
}
Class American:People
{
public new void GuoJi()//用new关键字来隐藏父类中的同名方法
{
Console.WriteLine("大家好,我来自美国!");
}
}
这样的话在主函数的入口处:
People p1=new People();
p1.GuoJi();
American p2=new American();//这里不能用People p2=new American();
p2.GuoJi();//注意这里调用的GuoJI()方法是子类自己的,不属于父类。
Console.Readkey();
运行后的显示结果是:
大家好,我来自中国!
大家好,我来自美国!