C++纯虚函数调用
添加时间:2013-6-5 点击量:
浏览本文之前,读者须要把握 C++ 虚函数的根蒂根基用法,以及懂得 C++ 的虚函数是怎么实现的,此为根蒂根基内容,不在本文的评论辩论局限。 在前次练习生口试中,口试官了我C++虚函数是如何实现的题目。我想读过 Inside the C++ Object Model 这本书的人对这点都是斗劲熟悉的,在申明过程中,他又问了我纯虚函数是什么,用来做什么。我在答复的过程中简单提了下“C++ 的纯虚函数在特别景象下是有可能会被调用的,具体的行动由 C++ 的标准库的实现决意”,后往返想起这句话,想了好久没想到具体的被调用的景象,幸好口试官没追问这个题目,不然我真得语塞了(当时几乎全部过程都是我在滚滚不绝的答复,口试官就一向嗯嗯嗯的状况)。趁如今斗劲闲又不想复习测验,就趁便写写代码,针对这个题目总结出一篇博客文章与大师交换。 起首,必须清楚的是纯虚函数本身是不该该被调用的!因为纯虚函数是用来定义接口的,有时辰基类本身找不到一个合情公道的实现,所以用虚函数的情势声明,让他的子类去做具体的实现。是以,若是纯虚函数被调用了,那必然是你的法度里呈现了逻辑上的错误,这是我们在工作中须要懂得和避免的,这也就是本文评论辩论的目标之一啦。 你知道,虚函数是经由过程指针或者引用来调用的,调用的具体函数由指针/引用的实际决意。而这个实际的对象,是可以由这个对象的内存块中的第一个值,vptr,指向虚函数表的指针来断定的。纯虚函数是属于基类的,所以要调用纯虚函数,这个指针所指的对象必须是基类。然则呢,抽象类(包含了纯虚函数的类)的对象是不容许被用户定义的,唔,这个规定看似严谨,C++ 怎么可能让你去调用纯虚函数,看本文的你也在好奇这个题目吧。不容许用户定义抽象类的对象,是的,不代表这种对象不克不及被机关!记得对象的机关过程,是先调用基类的机关函数,再调用子类的机关函数,也就是先机关基类对象,再机关子类对象,对象的析构我就不提了哈。也就是说,在基类的机关函数里调用的任何虚函数,都是调用基类本身的虚函数,而不是子类的虚函数,噢!漏洞就在这里! 当然,若是你测验测验写下如许的代码:
class Base{
public:
virtual void foo()=0;
Base() { foo(); } // 调用纯虚函数
};
class Derived: Base{
void foo() { }
};
int main() {
Derived d;
} 很荣幸的,编译器能发明错误并向你吐槽,以下是我应用CodeBlocks(自带MinGw的,含基于gcc
4.7.1的编译器)编译获得的一个警告和一个链接错误:编译警告:warning: pure virtual virtual void Base::foo() called constructor 链接错误:undefined reference to `Base::foo()
然则很不幸的,实际的应用中代码往往错杂得多,使得编译器无法在编译的时辰发明题目。批改上方的代码如下,就可以成功的调用到虚函数了: class Base{
public:
virtual void foo()=0;
Base() { call_foo();}
void call_foo() { foo(); }
};
class Derived: Base{
void foo() { }
};
int main() {
Derived d;
} 运行后获得的成果为:
哈哈好奇心终于获得了满足了!总结起来,其实还是 Item 9: Never call virtual functions during
construction or destruction. ( The third edition of Scott Meyers popular book,
Effective C++). 最后趁便提一下,在 C++ 11 的标准文档【ISO/IEC 14882:2011(E)】中,也有相干的描述: (10.4.6) Member functions can be called a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) such a constructor (or destructor) is undefined. 也就是说,纯虚函数调用的行动是不决义的,而 gcc 的默认实现则是终止法度,输出相干的信息。 参考链接: http://www.artima.com/cppsource/nevercall.html http://blogs.msdn.com/b/oldnewthing/archive/2004/04/28/122037.aspx 参考册本: Effective C++, 3rd Edition, Scott Meyers ISO/IEC 14882:2011(E)
Pony279原创博文,转载请注明出处 http://www.cnblogs.com/Pony279/archive/2013/06/04/3117955.html
文艺不是炫耀,不是花哨空洞的文字堆砌,不是一张又一张的逆光照片,不是将旅行的意义转化为名牌包和明信片的物质展示;很多时候它甚至完全不美——它嘶吼、扭曲,它会痛苦地抽搐,它常常无言地沉默。——艾小柯《文艺是一种信仰》
浏览本文之前,读者须要把握 C++ 虚函数的根蒂根基用法,以及懂得 C++ 的虚函数是怎么实现的,此为根蒂根基内容,不在本文的评论辩论局限。
在前次练习生口试中,口试官了我C++虚函数是如何实现的题目。我想读过 Inside the C++ Object Model 这本书的人对这点都是斗劲熟悉的,在申明过程中,他又问了我纯虚函数是什么,用来做什么。我在答复的过程中简单提了下“C++ 的纯虚函数在特别景象下是有可能会被调用的,具体的行动由 C++ 的标准库的实现决意”,后往返想起这句话,想了好久没想到具体的被调用的景象,幸好口试官没追问这个题目,不然我真得语塞了(当时几乎全部过程都是我在滚滚不绝的答复,口试官就一向嗯嗯嗯的状况)。趁如今斗劲闲又不想复习测验,就趁便写写代码,针对这个题目总结出一篇博客文章与大师交换。
起首,必须清楚的是纯虚函数本身是不该该被调用的!因为纯虚函数是用来定义接口的,有时辰基类本身找不到一个合情公道的实现,所以用虚函数的情势声明,让他的子类去做具体的实现。是以,若是纯虚函数被调用了,那必然是你的法度里呈现了逻辑上的错误,这是我们在工作中须要懂得和避免的,这也就是本文评论辩论的目标之一啦。
你知道,虚函数是经由过程指针或者引用来调用的,调用的具体函数由指针/引用的实际决意。而这个实际的对象,是可以由这个对象的内存块中的第一个值,vptr,指向虚函数表的指针来断定的。纯虚函数是属于基类的,所以要调用纯虚函数,这个指针所指的对象必须是基类。然则呢,抽象类(包含了纯虚函数的类)的对象是不容许被用户定义的,唔,这个规定看似严谨,C++ 怎么可能让你去调用纯虚函数,看本文的你也在好奇这个题目吧。不容许用户定义抽象类的对象,是的,不代表这种对象不克不及被机关!记得对象的机关过程,是先调用基类的机关函数,再调用子类的机关函数,也就是先机关基类对象,再机关子类对象,对象的析构我就不提了哈。也就是说,在基类的机关函数里调用的任何虚函数,都是调用基类本身的虚函数,而不是子类的虚函数,噢!漏洞就在这里!
当然,若是你测验测验写下如许的代码:
class Base{
public:
virtual void foo()=0;
Base() { foo(); } // 调用纯虚函数
};
class Derived: Base{
void foo() { }
};
int main() {
Derived d;
}
public:
virtual void foo()=0;
Base() { foo(); } // 调用纯虚函数
};
class Derived: Base{
void foo() { }
};
int main() {
Derived d;
}
很荣幸的,编译器能发明错误并向你吐槽,以下是我应用CodeBlocks(自带MinGw的,含基于gcc
4.7.1的编译器)编译获得的一个警告和一个链接错误:
4.7.1的编译器)编译获得的一个警告和一个链接错误:
编译警告:warning: pure virtual virtual void Base::foo() called constructor
链接错误:undefined reference to `Base::foo()
然则很不幸的,实际的应用中代码往往错杂得多,使得编译器无法在编译的时辰发明题目。批改上方的代码如下,就可以成功的调用到虚函数了:
class Base{
public:
virtual void foo()=0;
Base() { call_foo();}
void call_foo() { foo(); }
};
class Derived: Base{
void foo() { }
};
int main() {
Derived d;
}
public:
virtual void foo()=0;
Base() { call_foo();}
void call_foo() { foo(); }
};
class Derived: Base{
void foo() { }
};
int main() {
Derived d;
}
运行后获得的成果为:
哈哈好奇心终于获得了满足了!总结起来,其实还是 Item 9: Never call virtual functions during
construction or destruction. ( The third edition of Scott Meyers popular book,
Effective C++).
construction or destruction. ( The third edition of Scott Meyers popular book,
Effective C++).
最后趁便提一下,在 C++ 11 的标准文档【ISO/IEC 14882:2011(E)】中,也有相干的描述:
(10.4.6) Member functions can be called a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) such a constructor (or destructor) is undefined.
也就是说,纯虚函数调用的行动是不决义的,而 gcc 的默认实现则是终止法度,输出相干的信息。
参考链接:
http://www.artima.com/cppsource/nevercall.html
http://blogs.msdn.com/b/oldnewthing/archive/2004/04/28/122037.aspx
参考册本:
Effective C++, 3rd Edition, Scott Meyers
ISO/IEC 14882:2011(E)
Pony279原创博文,转载请注明出处 http://www.cnblogs.com/Pony279/archive/2013/06/04/3117955.html