虚函数

来源:互联网 发布:常见端口协议号 编辑:程序博客网 时间:2024/05/29 18:00

//今天深刻理解了虚函数和纯虚函数的作用和用法  
//如果子类实现了虚函数则调用子类的方法,  
//如果子类没有实现该函数则调用父类的方法。  
//究竟怎么用呢:  
假如CChild 派生自 CMan ,有个虚函数 Eat();

CMan m_man;
CChild m_child;
//这才是使用的精髓,如果不定义基类的指针去使用,没有太大的意义
CMan *p ;
p = &m_man ;
p->Eat(); //始终调用CMan的Eat成员函数,不会调用 CChild 的
p = &m_child;
p->Eat(); //如果子类实现了该方法,则始终调用CChild的Eat函数
//不会调用CMan 的 Eat 方法 如果子类没有实现该函数
//则调用CMan的Eat函数
//呵呵,就这些了,还得用心体会
//纯虚函数就是基类只定义了函数体,没有实现过程 定义方法如下
// virtual void Eat() = 0; 直接=0 不要 在cpp中定义就可以了
//纯虚函数相当于接口,不能直接实例话,需要派生类来实现函数定义
//有的人可能在想,定义这些有什么用啊 ,我觉得很有用
//比如 你想描述一些事物的属性给别人,而自己不想去实现,就可以定
//义为纯虚函数。说的再透彻一些。比如盖楼房,你是老板,你给建筑公司
//描述清楚你的楼房的特性,多少层,楼顶要有个花园什么的
//建筑公司就可以按照你的方法去实现了,如果你不说清楚这些,可能建筑
//公司不太了解你需要楼房的特性。用纯需函数就可以很好的分工合作了
//你觉得有道理吗?

C++复习——虚函数                                    
虚函数是C++中实现多态的机制。下面通过几个小程序实验来复习一下虚函数的概念用法。

#include

class A
{
public:
 virtual void f() { cout << "A::f()" << endl; }
};

class B : public A
{
public:
 void f() { cout << "B::f()" << endl; }
};

int main()
{
 A *a = new B;
 a->f();
 return 0;
}

在这个实验中a虽然是指向A,但调用的f()却是B的。

在基类中声明的虚函数在派生类中也是虚的,即使没有加上virtual关键字,例如:

#include

class A
{
public:
 virtual void f() { cout << "A::f()" << endl; }
};

class B : public A
{
public:
 void f() { cout << "B::f()" << endl; } //未加virtual关键字,实际上也是虚的
};

class C: public B
{
public:
 void f() { cout << "C::f()" << endl; } //未加virtual关键字,实际上也是虚的
};

int main()
{
 A *a = new B;
 a->f(); //调用的是B的f()
 A *a1 = new C;
 a1->f(); //调用的是C的f()
 B *b = new C;
 b->f(); //这里调用的也是C的f(),说明B的f()也是虚的
 return 0;
}


基类的析构函数必须是虚的,例如:

#include

class A
{
public:
 A() { p = new char[10]; cout << "A()" << endl; }
 ~A() { delete [] p; cout << "~A" << endl; }
private:
 char *p;
};

class B : public A
{
public:
 B() { p1 = new char[20]; cout << "B()" << endl; }
 ~B() { delete [] p1; cout << "~B" << endl; }
private:
 char *p1;
};

int main()
{
 A *a = new B;
 delete a;
 return 0;
}

运行结果:
A()
B()
~A()

也就是说B的析构函数并未被调用,这是多么严重的事情啊!看看加了virtual之后的情况:

#include

class A
{
public:
 A() { p = new char[10]; cout << "A()" << endl; }
 virtual ~A() { delete [] p; cout << "~A" << endl; }
private:
 char *p;
};

class B : public A
{
public:
 B() { p1 = new char[20]; cout << "B()" << endl; }
 ~B() { delete [] p1; cout << "~B" << endl; }
private:
 char *p1;
};
                                             C++中虚函数学习笔记
                                                                                       

因为最近学习C++的面向对象,所以了解了面向对象的三大特点: 封装、继承、多态性,学习多态性的时候,首先涉及的就是虚函数,我就把我学习虚函数的一些想法记录下来。
虚函数是为了实现某种功能而假设的函数,虚函数只能是类中的一个成员函数,不能是静态成员,使用关键字virtual用于在类中说明改函数是虚函数。 虚函数更是为了实现面向对象的多态性而产生的,使用虚函数和多态性能够简化代码长度,支持更简单的顺序,便于程序的调试,维护。
虚函数的定义方法:
class A
{
    public:
        virtual void fun();    //define virtual function
};
void A::fun() { ... }    //member function describe

上面定义了一个虚函数,然后在类体外进行了函数的具体描述。

在类的继承当中,当基类中声明了某个虚函数,即使在派生类中没有声明虚函数,那么在以后的继承结构中都是虚函数,当然如果有多重继承,在每个派生类中还是推荐对每个虚函数进行显式的声明。

为了说明虚函数在派生类中的应用,我写段代码作例子:

//test.cpp
//code by heiyeluren

#include stdio
class cbase
{
public:
 virtual void vfoo()
 {
  printf(vfoo from cbase//n);
 };
 void foo()
 {
  printf(foo from cbase//n);
 }
};
class cderivd : public cbase
{
public:
 virtual void vfoo()
 {
  printf(vfoo from cderivd//n);
 };
 void foo()
 {
  printf(foo from cderivd//n);
 };
};

int main(int argc, char* argv[])
{
 cbase* pbase = new cderivd();
 pbase->foo(); //非虚函数,根据指针类型决定调用哪个foo,本例指针类型为cbase,所以调用的是cbase::foo()
 pbase->vfoo(); //虚函数,调用的是派生类的vfoo
 delete pbase;

 cderivd* pd = new cderivd();
 pd->foo(); //非虚函数,本例指针类型为cderivd*,所以调用cderivd::foo();
 pd->vfoo();
 delete pd;

 cderivd d;
 d.foo();
 d.vfoo();
 ((cbase)d).foo();//将d强行切割为cbase,这时调用的无论是foo还是vfoo都将是base的
 ((cbase)d).vfoo();

 getchar();
 return 0;
}

程序在DevCPP下编译通过,输出:
foo from cbase
vfoo from cderivd
foo from cderivd
vfoo from cderivd
foo from cderivd
vfoo from cderivd
foo from cbase
vfoo from cbase

那么就能看出那个是虚函数,那个不是了吧。

int main()
{
 A *a = new B;
 delete a;
 return 0;
}

运行结果:
A()
B()
~B()
~A()

好的B的析构被调用了,还要注意类被构造析构的是进栈出栈的顺序。

再看一下纯虚函数。纯虚函数只是提供了一个接口罢了,她告诉使用者我的派生类中都会有这个函数。

#include

class A
{
public:
 virtual void f1() = 0;
 virtual void f2() { cout << "A::f2()" << endl; }
};

class B : public A
{
public:
 void f1() { cout << "B::f1" << endl; }
 void f2() { cout << "B::f2()" << endl; }
};

int main()
{
 A *a = new B;
 a->f1();
 a->f2();
 return 0;
}