C++基础:虚函数、重载、覆盖、隐藏<转>
转自:http://www.2cto.com/kf/201404/291772.html
虚函数总是跟多态联系在一起,引入虚函数可以使用基类指针对继承类对象进行操作!
虚函数:继承接口(函数名,参数,返回值),但是实现不继承(函数体)
非虚函数:继承接口,也继承实现;
1)虚析构函数(当一个类打算作为基类使用时候,其析构函数必须是虚函数)
构造函数可以为虚函数吗? 不可以,在生成对象的时候,必须向编译器明确指定要生成什么类型的对象,因而不存在虚函数的问题;只有当对象已经存在,我用什么接口去操作它的问题;
例子:
class A
{
public:
A();
virtual~A();
};
class B: public A
{
public:
B();
~B();
};
int main()
{
A *pA=new B; //调用B的构造函数
delete pA;
return 0;
}
这里通过指针A去调用B类的析构函数,但是如果 ~A()不是虚析构函数,就不存在多态,就会去调用A中的析构函数,最后结果可能是B对象中的A成分被析构了,其他 还残留;所以当一个类作为基类时候,其析构函数必须是虚函数,这样防止出现析构不完全的情况;
2)当虚函数出现在构造、析构函数中时(即在构造函数中调用虚函数),函数退化为普通函数。为什么? <>中条款
例子:(转自<>中条例9)
class Transaction
{
public:
Transaction();
virtual void LogTransaction() const = 0;
// ...
};
Transaction::Transaction()
{
// ...
LogTransaction();
}
class BuyTransaction : public Transaction
{
public:
virtual void LogTransaction() const;
// ...
};
这里调用BuyTransaction的构造函数,因为BuyTransaction是继承类所以先调用基类的构造函数,此时派生类独有的那部分还未初始化,<>中这么解释:“这个对象内的BuyTransaction成分还未初始化,最安全的办法是当他不存在,对象在derived成分还未初 始化时该对象不会成为一个derived对象”所以Transaction 的构造函数会调用基类的 LogTransaction() const;而且此处是个纯虚函数,会报错
3)虚函数与覆盖,重载,隐藏
重载首先出现在非继承关系当中,当同一个类中,两个函数的参数不同,名字相同,返回值类型无所谓(函数返回值不作为重载的参考,因为函数调用时候不出现返回值);
注意两个函数可以仅仅因为const与非const的差别来实现重载;
虚函数与覆盖均出现在一个继承体系中,覆盖针对的是普通函数,当父类子类中出现同名(相同返回值,相同参数,相同函数名)要求绝对一致;
虚函数在父类子类中,首先在父类中声明该函数为virtual,那么子类可以重新定义该函数的实现,这里主要涉及多态,就是覆盖的情况加上virtual,通过指针或者引用实现多态;
隐藏显得简单粗暴,在继承类中只要出现于父类同名(只要求同样的函数名/变量名,其他返回值,virtual 非virtual不管)的函数,则用对象调用同名函数时候,基类对应的同名函数、变量隐藏,如果要访问其父类的同名成员应该明确使用 基类名::成员来访问;
例子:
class A
{
public:
virtual ~A(){};
void process(int i,char c); //重载,编译期间即可确定该调用哪个函数
char process(double d,int c); //只要函数名相同,返回无所谓,参数不同
void process(int i);
void process(int i)const; // 此处相当于void process(const A *this,int i);
void process(consttint i); //这里仅仅因为const属性不同即可实现重载
virtual int foo(int, char){...};
int foo2(){};
void foo3(int,int ){};
}
class B: public A
{
public:
int foo(int ,char){...}; //虚函数,这里函数接口要严格一致(大部分编译器要求返回值也要一致)
int process(){...}; //隐藏基类函数
int foo2(){}; // 这里不含虚属性,会覆盖
int foo3(){return 0;}; //会隐藏A类的foo3
}
int main()
{
B b;
A *pA=&b;
pA->foo2(); //这里调用A类的foo2();不涉及多态;
pA->foo(3,'c'); //B类foo() 涉及多态
}
总结:
1)覆盖与虚函数是一对兄弟,要求函数的返回值,函数名,参数严格一致,虚函数是覆盖加上virtual的情况;
2) 隐藏是覆盖的推广,覆盖是隐藏的特例,只要求函数名一样,其他不管,在继承体系中,子类的同名函数会将父类的同名函数隐藏;
3)当使用指针时候,指向基类的指针会根据实际对象的类型,选择相应的虚函数执行,如果派生类没有重新定义基类的虚函数,那么依然执行基类的虚函数;
4)当不存在虚函数的情况下,使用基类的指针,不会下降到派生类中去搜索函数;所以virtual属性相当于告诉基类指针:当执行我时,请到相应对象中搜索对应的虚函数;
5)纯虚函数所在的类是抽象类,不能实例化,定义了纯虚函数意味着这个函数只能为父类,其负责定义接口而不负责实现;
6)当使用对象来调用相应的函数时候,主要考虑的是对基类同名函数的隐藏(包括覆盖),而不需要考虑多态;
7)注意构造析构函数中不能调用虚函数,当执行派生类的构造函数时候,先构造的是其基类成分,再执行派生类成分的构造,虚函数此时无意义;
8)c++是个细节非常多,非常复杂的语言;
C++基础:虚函数、重载、覆盖、隐藏<转>的更多相关文章
- C++重载覆盖隐藏
写一个程序,各写出重载覆盖 1 // // main.cpp // 2013-7-17作业2 // // Created by 丁小未 on 13-7-17. // Copyright (c) 201 ...
- C++11显式虚函数重载
[C++11显式虚函数重载] 在子类中给重载的虚函数加上override, 可以让编译器检察基类是否有这一虚函数.此功能适用于当基类原有的虚函数发生变化,即相当于编译期检察. 而基类,可以给函数加上f ...
- C++ 11 学习3:显示虚函数重载(override)
5.显示虚函数重载 在 C++ 里,在子类中容易意外的重载虚函数.举例来说: struct Base { virtual void some_func(); }; struct Derived : B ...
- c++ 继承 虚函数与多态性 重载 覆盖 隐藏
http://blog.csdn.net/lushujun2011/article/details/6827555 2011.9.27 1) 定义一个对象时,就调用了构造函数.如果一个类中没有定义任何 ...
- 虚函数重载(overwrite) 继承覆盖问题
引言 类接口需要添加默认参数,以适应不同情况调用, 但是clang-tidy 不允许在接口上设置默认参数,ps: 可能担心继承类里接口重新设置新默认参数而导致误用的情况 #include <st ...
- c/c++:重载 覆盖 隐藏 overload override overwrite
http://www.cnblogs.com/qlee/archive/2011/07/04/2097055.html 成员函数的重载.覆盖与隐藏成员函数的重载.覆盖(override)与隐藏很容易混 ...
- c++中 重载 覆盖 隐藏的区别 附加 mutable笔记
成员函数被重载的特征有: 1) 相同的范围(在同一个类中): //2) 函数名字相同: 3) 参数不同: 4) virtual关键字可有可无. 覆盖的特征有: 1) 不同的范围(分别位于派生类与基类) ...
- C++基础--虚函数和纯虚函数
虚函数的一种重要的应用是在子类重写父类方法上,一般都是在父类中声明的时候用关键字virtual修饰. 在C++中,一个父类的对象指针是可以指向子类的实例化对象,这个时候可以用该对象指针来访问父类的成员 ...
- C++中的重载,隐藏,覆盖,虚函数,多态浅析
直到今日,才发现自己对重载的认识长时间以来都是错误的.幸亏现在得以纠正,真的是恐怖万分,雷人至极.一直以来,我认为重载可以发生在基类和派生类之间,例如: class A { public: void ...
随机推荐
- ORM取数据很简单!是吗?
简介 几乎任何系统都以某种方式与外部数据存储一起运行.大多数情况下,外部数据存储是一个关系数据库,并且在实现时通常将数据提取任务委托给某些 ORM. 尽管 ORM 包含很多 routine 代码,但是 ...
- 201621123016 《Java程序设计》第十一周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1. 源代码阅读:多线程程序BounceThread 1.1 BallR ...
- lightoj1063【求割点】
题意不懂啊...... 只知道求割点. #include <bits/stdc++.h> using namespace std; typedef long long LL; typede ...
- Telnet 对memcached进行数据操作
连接Telnet 127.0.0.1 11211 存储数据 add news 0 1 8 (news为数据名称,1为存储的时间,当为0的时候则为永久储存,永久缓存最多为30天,8为长度) aaaaaa ...
- 考虑实现Comparable接口
考虑实现Comparable接口 compareTo方法没有在Object中声明.相反,它是Comparable接口中唯一的方法.compareTo方法不但允许进行简单的等同性比较,而且允许执行顺 ...
- mysql之SQL入门与提升(三)
今天继续讲mysql数据库 先创建一张Persons表 CREATE TABLE Persons(P_Id int NOT NULL,LastName varchar(255) NOT NULL,Fi ...
- Python-1-基础
获取用户输入 >>> x = input("x: ") x: 34 >>> y = input("y: ") y: 42 & ...
- redis集群模式
1 弊端和优势 弊端:相比单机模式,集群模式会在节点之间同步数据,会降低20%-30%的性能,同时增加架构复杂性,提高硬件成本和学习成本. 优势:增加冗余,避免单点故障.单机模式如果要重启,必然会丢失 ...
- [已读]JavaScript模式
主要是介绍各种继承和设计模式.第一章是讲编程规范,然后里面讲到了使用new Function替代eval
- I/O————字符流和流的关闭
Reader字符输入流 Writer字符输出流 用于字符的形式读取和写入数据 FileReader与FileWriter分别是Reader与Writer的子类 public class CharScr ...