老葱讲座

 

一根老葱(17757899) 15:00:29
例如一个类
class A
{
public:
    virtual void foo() { cout << "A::foo() is called" << endl;}
};

这个class A是一个基类 

然后呢:我派生一个B 

class B: public A
{
public:
    virtual void foo() { cout << "B::foo() is called" << endl;}
};
 
问问大家 
A * a = new B();
a->foo(); 
这里的 a->foo(); 是哪个? 

一根老葱(17757899) 15:03:02
这里的 a->foo();  看起来呢是调用基类的 foo() 
其实呢是调用 class B 的foo() 

//============================//
一根老葱(17757899) 15:06:39
void fun(A * a)
{
    a->foo();  // 被调用的是A::foo() 还是B::foo()?
}

一根老葱(17757899) 15:08:44
因为foo()是个虚函数,所以在fun这个函数中,
只根据这段代码,
无从确定这里被调用的是A::foo()还是B::foo(),
但是可以肯定的说:如果a指向的是A类的实例,则A::foo()被调用,
如果a指向的是B类的实例,则B::foo()被调用。 
这种同一代码可以产生不同效果的特点,被称为“多态”。
他是根据实际指针来绝定动作的 

  
一根老葱(17757899) 15:13:08
纯虚函数 也说说把 

class A
{
public:
    virtual void foo()=0;   // =0标志一个虚函数为纯虚函数
};

这个时候 就是声明为纯虚 

纯虚函数的意思是:我是一个抽象类!
不要把我实例化!纯虚函数用来规范派生类的行为,
实际上就是所谓的“接口”。它告诉使用者,
我的派生类都会有这个函数 

一根老葱(17757899) 15:15:18
析构函数也可以是虚的,甚至是纯虚的 
当一个类打算被用作其它类的基类时,它的析构函数必须是虚的。 
记住这些就差不多了 
构造函数不能是虚的 

一根老葱(17757899) 15:19:39
在你设计一个基类的时候,如果发现一个函数需要在派生类里有不同的表现,
那么它就应该是虚的。从设计的角度讲,出现在基类中的虚函数是接口,
出现在派生类中的虚函数是接口的具体实现。通过这样的方法,
就可以将对象的行为抽象化 

其实新人不该叫 虚函数 
虚函数 翻译的不好 
我喜欢叫虚函数为虚拟函数 
虚拟一个动作  

一根老葱(17757899) 15:44:13
1.虚函数仅适用于有继承关系的类对象, 所以只有类的成员函数才能说明为虚函数. 
2.静态成员函数不能是虚函数. 
3.内联函数不能是虚函数. 
4.构造函数不能是虚函数. 
5.析构函数可以是虚函数. 

虚函数最主要的缺点是执行效率较低 
原因是:
编译器发现一个类中有虚函数,编译器会立即为此类生成虚拟函数表 VTABLE.
虚拟函数表的各表项为指向对应虚拟函数的指针。
 
编译器在此类中隐含插入一个指针VPTR 
在调用此类的构造函数时,在类的构造函数中,编译器会隐含执行VPTR与VTABLE的关联代码,
将VPTR指向对应的VTable。这就将类与此类的VTABLE联系了起来。
实现机制导致了高灵活性低效率 
*/
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值