转自: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++基础:虚函数、重载、覆盖、隐藏<转>的更多相关文章

  1. C++重载覆盖隐藏

    写一个程序,各写出重载覆盖 1 // // main.cpp // 2013-7-17作业2 // // Created by 丁小未 on 13-7-17. // Copyright (c) 201 ...

  2. C++11显式虚函数重载

    [C++11显式虚函数重载] 在子类中给重载的虚函数加上override, 可以让编译器检察基类是否有这一虚函数.此功能适用于当基类原有的虚函数发生变化,即相当于编译期检察. 而基类,可以给函数加上f ...

  3. C++ 11 学习3:显示虚函数重载(override)

    5.显示虚函数重载 在 C++ 里,在子类中容易意外的重载虚函数.举例来说: struct Base { virtual void some_func(); }; struct Derived : B ...

  4. c++ 继承 虚函数与多态性 重载 覆盖 隐藏

    http://blog.csdn.net/lushujun2011/article/details/6827555 2011.9.27 1) 定义一个对象时,就调用了构造函数.如果一个类中没有定义任何 ...

  5. 虚函数重载(overwrite) 继承覆盖问题

    引言 类接口需要添加默认参数,以适应不同情况调用, 但是clang-tidy 不允许在接口上设置默认参数,ps: 可能担心继承类里接口重新设置新默认参数而导致误用的情况 #include <st ...

  6. c/c++:重载 覆盖 隐藏 overload override overwrite

    http://www.cnblogs.com/qlee/archive/2011/07/04/2097055.html 成员函数的重载.覆盖与隐藏成员函数的重载.覆盖(override)与隐藏很容易混 ...

  7. c++中 重载 覆盖 隐藏的区别 附加 mutable笔记

    成员函数被重载的特征有: 1) 相同的范围(在同一个类中): //2) 函数名字相同: 3) 参数不同: 4) virtual关键字可有可无. 覆盖的特征有: 1) 不同的范围(分别位于派生类与基类) ...

  8. C++基础--虚函数和纯虚函数

    虚函数的一种重要的应用是在子类重写父类方法上,一般都是在父类中声明的时候用关键字virtual修饰. 在C++中,一个父类的对象指针是可以指向子类的实例化对象,这个时候可以用该对象指针来访问父类的成员 ...

  9. C++中的重载,隐藏,覆盖,虚函数,多态浅析

    直到今日,才发现自己对重载的认识长时间以来都是错误的.幸亏现在得以纠正,真的是恐怖万分,雷人至极.一直以来,我认为重载可以发生在基类和派生类之间,例如: class A { public: void ...

随机推荐

  1. ORM取数据很简单!是吗?

    简介 几乎任何系统都以某种方式与外部数据存储一起运行.大多数情况下,外部数据存储是一个关系数据库,并且在实现时通常将数据提取任务委托给某些 ORM. 尽管 ORM 包含很多 routine 代码,但是 ...

  2. 201621123016 《Java程序设计》第十一周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线程 1. 源代码阅读:多线程程序BounceThread 1.1 BallR ...

  3. lightoj1063【求割点】

    题意不懂啊...... 只知道求割点. #include <bits/stdc++.h> using namespace std; typedef long long LL; typede ...

  4. Telnet 对memcached进行数据操作

    连接Telnet 127.0.0.1 11211 存储数据 add news 0 1 8 (news为数据名称,1为存储的时间,当为0的时候则为永久储存,永久缓存最多为30天,8为长度) aaaaaa ...

  5. 考虑实现Comparable接口

    考虑实现Comparable接口   compareTo方法没有在Object中声明.相反,它是Comparable接口中唯一的方法.compareTo方法不但允许进行简单的等同性比较,而且允许执行顺 ...

  6. mysql之SQL入门与提升(三)

    今天继续讲mysql数据库 先创建一张Persons表 CREATE TABLE Persons(P_Id int NOT NULL,LastName varchar(255) NOT NULL,Fi ...

  7. Python-1-基础

    获取用户输入 >>> x = input("x: ") x: 34 >>> y = input("y: ") y: 42 & ...

  8. redis集群模式

    1 弊端和优势 弊端:相比单机模式,集群模式会在节点之间同步数据,会降低20%-30%的性能,同时增加架构复杂性,提高硬件成本和学习成本. 优势:增加冗余,避免单点故障.单机模式如果要重启,必然会丢失 ...

  9. [已读]JavaScript模式

    主要是介绍各种继承和设计模式.第一章是讲编程规范,然后里面讲到了使用new Function替代eval

  10. I/O————字符流和流的关闭

    Reader字符输入流 Writer字符输出流 用于字符的形式读取和写入数据 FileReader与FileWriter分别是Reader与Writer的子类 public class CharScr ...