虚函数

C++中不能被声明为虚函数
    普通函数(非成员函数),构造函数,内联成员函数,静态成员函数,友元函数。
    1) 虚函数用于基类和派生类,普通函数所以不能
    2) 构造函数不能是因为虚函数采用的是虚调用的方法,允许在只知道部分信息的情况的工作机制,特别允许调用只知道接口而不知道对象的准确类型的方法,但是调用构造函数即使要创建一个对象,
那势必要知道对象的准确类型。
    3) 内联成员函数的实质是在调用的地方直接将代码扩展开
    4) 继承时,静态成员函数是不能被继承的,它只属于一个类,因为也不存在动态联编等
    5) 友元函数不是类的成员函数,因此也不能被继承

 

 每个存在虚函数的类都要有一个4字节的指针指向自己的虚函数表,虚继承将产生一个虚类指针

class a
{
    virtual void func();
};

class b:public virtual a 
{
    virtual void foo();
};

sizeof(a) = 4
sizeof(b) = 12

class a
{
    virtual void func();
};

class b:public a 
{
    virtual void foo();
};
sizeof(a) = 4
sizeof(b) = 8
View Code

 

虚函数声明和定义和普通的类成员函数一样,只是在返回值之前加入了关键字“virtual”声明为虚函数。而虚函数是实现多态的重要手段,意思是只有对虚函数的调用才能动态决定调用哪一个函数,这是相对于普通成员函数而言的,普通的成员函数在编译阶段就能确定调用哪一个函数

#include <stdio.h>

class A {
public:
    void fn() { printf("fn in A\n"); }
    virtual void v_fn() { printf("virtual fn in A\n"); }
};

class B : public A {
public:
    void fn() { printf("fn in B\n"); }
    virtual void v_fn() { printf("virtual fn in B\n"); }
};

int main() {
    A *a = new B();
    a->fn();
    a->v_fn();

    B bb;
    A& aaa = bb;
    aaa.fn();
    aaa.v_fn();
    
    return 0;
}
View Code

 

虚继承的提出就是为了解决多重继承时,可能会保存两份副本的问题,也就是说用了虚继承就只保留了一份副本,但是这个副本是被多重继承的基类所共享的

#include <stdio.h>

class A {
public:
    int a;
};

class B : virtual public A {
};

class C : virtual public A {
};

class D : public B, public C{
};


int main() {
    printf("%d\n", sizeof(D));
    return 0; 
}
View Code

 
C++中的多态性具体体现在运行和编译两个方面。运行时多态是动态多态,其具体引用的对象在运行时才能确定。编译时多态是静态多态,在编译时就可以确定对象使用的形式。C++中,实现多态有以下方法:虚函数,抽象类,重载,覆盖,模版。
动态多态性:在程序运行过程中才动态地确定操作所针对的对象,又称为运行时的多态性,一般通过虚函数(virtual function)+继承实现,关键字virtual。
静态多态性:函数重载、运算符重载

 

1) 虚函数实现多态所必须,父类类型的指针指向子类的实例,执行的时候会执行之类中定义的函数。    
2) 如果有子类的话,析构函数必须是虚函数。否则析构子类类型的指针时,析构函数有可能不会被调用到。
3) 编译器根据虚函数表找到恰当的虚函数。对于一个父类的对象指针类型变量,如果给他赋父类对象的指针,那么他就调用父类中的函数,如果给他赋子类对象的指针,他就调用子类中的函数。函数执行之前查表。
4) 虚函数表是针对类的,一个类的所有对象的虚函数表都一样。    
5) 纯虚函数就是定义了一个虚函数但并没有实现,原型后面加"=0"。包含纯虚函数的类都是抽象类,不能生成实例。
6) 每个对象的虚函数表指针是在构造函数中初始化的,因为构造函数没执行完,所以虚函数表指针还没初始化好,构造函数的虚函数不起作用。
7) 就算调用虚函数也不起作用,调用虚函数同调用一般的成员函数一样。
8) 析构函数中调用虚函数也不起作用,调用虚函数同调用一般的成员函数一样。析构函数的顺序是先派生类后基类,有可能内容已经被析构没了,所以虚函数不起作用。
9) 虚继承是为了解决多重继承出现菱形继承时出现的问题。例如:类B、C分别继承了类A。类D多重继承类B和C的时候,类A中的数据就会在类D中存在多份。通过声明继承关系的时候加上virtual关键字可以实现虚继承见的是stack和queue,他们的底层存储都是用deque完成的,再在deque上封装一层接口以满足stack和queue的要求。

posted on 2014-10-22 15:17  kangbry  阅读(355)  评论(0编辑  收藏  举报

导航