关于inline关键字:effective c++ item33:明智运用inlining。说到:inline指令就像register指令一样,只是对编译器的一种提示,而不是一个强制命令,意思是编译器可自由决定要不要忽略你的inline指令。大部分编译器会拒绝将复杂的(也就是内含循环或递归调用的)函数inline话,而所有(除了最平凡,几乎什么也没做)的虚拟函数,都追阻止inlining的进行。这应该不会引起太多的惊讶,因为virtual意味着”等待,直到执行时期再确定应该调用哪一个函数“,而inline却意味着”在编译阶段,将调用动作以被调用函数的主体取代之“。如果编译器做决定时,尚不知道该调用哪一个函数,你就很难责成他们做出一个inline函数。

上面叙述总结起来:一个表面上的linline函数,实际上是否为inline,必须视编译器耳钉,幸运的是大部分编译器都有一个诊断功能,如果无法按照你所要求的函数inline化,会给你一个警告信息。

关于virtual inline function一篇文章:

原文:http://www.drdobbs.com/cpp/standard-c-programming-virtual-functions/184403747

曾经,我们常常在谈及C++时听到一个问题:“虚函数真的应该被申明为内联吗?”现在,
我们很少再听到这个问题了。反过来,我们现在听到的是“你不应该将print()函数内联。
将虚函数申明为内联是错误的。”

这么说有两个主要理由:(1)虚函数是在运行期判决的,而内联是编译期行为,所以不能从
这个(内联)申明上得到任何好处;(2)将虚函数申明为内联将造成此函数在可执行文件中
有多份拷贝,因此我们为一个无论如何都不能内联的函数付出了在空间上的处罚(WQ注,
所谓的内联函数非内联问题)。显然没脑子。

只是它并不真的正确。反思一下理由(1):在很多情况下,虚函数是静态判决的--尤其是
派生类的虚函数调用它的基类版本时。为什么会那么做?封装。一个很好的例子是析构函
数的静态调用链:基类的析构函数被派生类的析构函数触发。除了最初的一个外,所有的
析构函数的调用都是被静态判决的。不让基类的虚析构函数内联,就不能从中获益。这会
造成很大的差别吗?如果继承层次很深,而又有大量的对象需要析构,(答案是)“是的
”。

另外一个例子不涉及析构函数。想像我们正在设计一个图书馆出借管理程序。我们已经将
“位置”放入抽象类LibraryMaterial。当申明print()函数为纯虚函数时,我们也提供其
定义:打印出对象的位置。

Only that's not really true. Let's take item (1) first: there are many cases in which a virtual function is resolved statically — essentially any time a derived class virtual method invokes the method of its base class(es). Why would one do that? Encapsulation. A good example is the static invocation chain of base class destructors triggered by the virtual resolution of a derived class destructor. All the destructor calls except for the initial resolution are resolved statically. Without making the base class virtual destructors inline, we cannot take advantage of this. Does it make much of a difference? If the hierarchy is deep and there are many objects destructed, yes.

For another example that does not use destructors, imagine that we are designing a library lending material hierarchy. We've factored the material's location into the abstractLibraryMaterial class. While we declare its print function as a pure virtual function, we also provide a definition: it prints out the material's location.

class LibraryMaterial {

private:

MaterialLocation _loc; // shared data

// ...

public:

// declares pure virtual function

inline virtual void print( ostream& = cout ) = 0;

};

// we actually want to encapsulate the handling of the

// location of the material within a base class

// LibraryMaterial print() method - we just don’t want it

// invoked through the virtual interface. That is, it is

// only to be invoked within a derived class print() method

inline void

LibraryMaterial::

print( ostream &os ) { os << _loc; }

(

Can a pure virtual function have an implementation?

转自:http://www.programmerinterview.com/index.php/c-cplusplus/pure-virtual-function/

The quick answer to that question is yes! A pure virtual function can have an implementation in C++ – which is something that even many veteran C++ developers do not know. So, using the SomeClass class from our example above, we can have the following code:

class SomeClass {
public:
virtual void pure_virtual() = 0; // a pure virtual function
// note that there is no function body
}; /*This is an implementation of the pure_virtual function
which is declared as a pure virtual function.
This is perfectly legal:
*/
void SomeClass::pure_virtual() {
cout<<"This is a test"<<endl;
}

Why would you want a pure virtual function to have an implementation?

It is actually pretty rare to see a pure virtual function with an implementation in real-world code, but having that implementation may be desirable when you think that classes which derive from the base class may need some sort of default behavior for the pure virtual function. So, for example, if we have a class that derives from our SomeClass class above, we can write some code like this – where the derived class actually makes a call to the pure virtual function implementation that is inherited:

//this class derives from SomeClass
class DerivedClass: public SomeClass { virtual void pure_virtual() { /*
Makes a call to the pure virtual function
implementation that is inside the SomeClass
class. This can happen because DerivedClass
may not have anything appropriate to define
for this function, so it just calls the SomeClass's
implementation
*/ SomeClass::pure_virtual(); } };

Something else that is definitely worth noting in the code above is the fact that the call to the “SomeClass::pure_virtual();” function is valid because of the fact that the pure_virtual function declaration is public in the SomeClass class. That call would also be valid if the pure_virtual function declaration is protected, because the DerivedClass does derive from the SomeClass class. However, if the pure_virtual function declaration was private in the SomeClass class, then a compiler error would result when the “SomeClass::pure_virtual();” call is made in the DerivedClass class, because it would obviously not have access to that function implementation.

Pure virtual functions can not have a definition inside the function declaration

If you do mistakenly try to give a declaration of a pure virtual function a definition as well, then the compiler will return an error when it comes across that code. Note that there is however an exception to this in Microsoft’s Visual C++ implementation, which specifically allows this. This is also known as an inline definition, which is completely different from the use of the inline keyword – which you can read about here Inline vs macro. So, suppose we have the following code:

class SomeClass {
public:
/*note that we added braces that are normally
associated with a function body and definition:
*/
virtual void pure_virtual() = 0 { }; //ERROR (except in MS VC++)
};

The code above is considered ill formed by the C++ 03 standard in Clause 10.4, paragraph 2, which says that “a function declaration cannot provide both a pure-specifier and a definition”.

Running the code above will actually result in a compiler error, because a pure virtual function can not have a definition within the declaration of the pure virtual function.

接着引入Book类;它的print()函数会输出书名、作者等等。在此之前,它先调用基类的L
ibraryMaterial::print()函数以显示位置信息。例如:

inline void

Book::

print( ostream &os )

{

// ok, this is resolved statically,

// and therefore is inline expanded ...

LibraryMaterial::print();

os << "title:" << _title

<< "author" << _author << endl;

}

AudioBook类从Book派生,引入了一个二选一的借出策略,并且加入了一些附加信息,比如
讲解员、格式等等。这些都将在它的print()函数中显示出来。在显示这些以前,它先调用
Book::print():

inline void

AudioBook::

print( ostream &os )

{

// ok, this is resolved statically,

// and therefore is inline expanded ...

Book::print();

os << "narrator:" << _narrator << endl;

}

在这个例子和析构函数的例子中,派生类的虚方法递增式地扩展其基类版本的功能,并以
调用链的方式被调用,只有最初一次调用是由虚体系决定的。这个没有被命名的继承树设
计模式,如果从不将虚函数申明为内联的话,显然会有些低效。

关于理由(2)的代码膨胀问题怎么说?好吧,思考一下。如果写出,

LibraryMaterial *p =

new AudioBook( "Mason & Dixon",

"Thomas Pynchon", "Johnny Depp" );

// ...

p->print();

此处的print()会内联吗?不,当然不会。这必须在运行期经过虚体系的判决。Okay。它会
导致此处的print()函数有它自己的定义体吗?也不会。调用被编译为类似于这种形式:

// Pseudo C++ Code

// Possible transformation of p->print()

( *p->_vptr[ 2 ] )( p );

那个2是print()函数在相应的虚函数表中的位置。因为这个对print()的调用是通过函数指
针_vptr[2]进行的,编译器不能静态决定被调用函数的位置,并且函数不能被内联。

当然,内联的虚函数print()的定义必须出现在可执行文件中的某处,代码才能正确执行。
也就是说,至少需要一个定义体,以便将它的地址放入虚函数表。编译器如何决定何时产
生那一个定义体的呢?一个实现策略是在产生那类的虚函数表时同时产生那个定义体。这
意味着针对为一个类所生成的每个虚函数表实例,每个内联的虚函数的一个实例也被产生

在可执行文件中,为一个类产生的虚函数表,实际上有多少个?啊,很好,问得好。C++标
准规定了虚函数在行为上的要求;但它没有规定实现虚函数上的要求。既然虚函数表的存
在不是C++标准所要求的,明显标准也没有进一步要求如何处理虚函数表以及生成多少次。
最佳的数目当然是“一次”。例如,Stroustrup的原始cfront实现版本,在大部份情况下
聪明地达成了这一点。 (Stan和Andy Koenig描述了其算法,发表于1990年3月,C++ Repo
rt,“Optimizing Virtual Tables in C++ Release 2.0.”)

此外,C++标准现在要求内联函数的行为要满足好象程序中只存在一个定义体,即使这个函
数可能被定义在不同的文件中。新的规则是说满足规定的实现版本,行为上应该好象只生
成了一个实例。一旦标准的这一点被广泛采用,对内联函数潜在的代码膨胀问题的关注应
该消失了。

C++社群中存在着一个冲突:教学上需要规则表现为简单的检查表vs实践中需要明智地依据
环境而运用规则。前者是对语言的复杂度的回应;后者,是对我们构造的解决方案的复杂
度的回应。何时将虚函数申明为内联的问题,是这种冲突的一个很好的例证。

http://www.cppblog.com/cuglij/archive/2007/04/26/22881.aspx

http://msdn.microsoft.com/en-us/magazine/cc301407.aspx

http://stackoverflow.com/questions/733737/are-inline-virtual-functions-really-a-non-sense

c++virtual inline 是否冲突的更多相关文章

  1. 虚函数 error LNK2001: 无法解析的外部符号 "public: virtual void __cdecl

    在虚函数后面加一对大括号 #ifndef CAFFE_CONV_DW_LAYER_HPP_ #define CAFFE_CONV_DW_LAYER_HPP_ #include <vector&g ...

  2. 基于Caffe的Large Margin Softmax Loss的实现(上)

    小喵的唠叨话:在写完上一次的博客之后,已经过去了2个月的时间,小喵在此期间,做了大量的实验工作,最终在使用的DeepID2的方法之后,取得了很不错的结果.这次呢,主要讲述一个比较新的论文中的方法,L- ...

  3. 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByName

    按照name属性获取多元素 -- getElementsByName 标准 DOM 1 定义在HTMLDocument Interface 中,原型NodeList getElementsByName ...

  4. 基于Caffe的DeepID2实现(下)

    小喵的唠叨话:这次的博客,真心累伤了小喵的心.但考虑到知识需要巩固和分享,小喵决定这次把剩下的内容都写完. 小喵的博客:http://www.miaoerduo.com 博客原文: http://ww ...

  5. 基于Caffe的DeepID2实现(中)

    小喵的唠叨话:我们在上一篇博客里面,介绍了Caffe的Data层的编写.有了Data层,下一步则是如何去使用生成好的训练数据.也就是这一篇的内容. 小喵的博客:http://www.miaoerduo ...

  6. Caffe源码解析3:Layer

    转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/ layer这个类可以说是里面最终的一个基本类了,深度网络呢就是 ...

  7. 自用debug单元

    将之前的内存查看单元小幅修改,加上文件操作和计时,组成了一个自用debug单元,使用方法如示例. 此单元便捷之处在于直接将#define DEBUG注释掉而无需改动源码,即可取消debug模式. #d ...

  8. Matrix Calculator

    表达式分析+矩阵+计算器+寄存器=矩阵计算器 怎么想起来搞这个呢.. //刚看龙书兴致勃勃要搞表达式分析 这个寄存器比较简陋,26字母+4缓存,//字母不分大小写 当然,不只能算矩阵,还能算数= = ...

  9. MMORPG大型游戏设计与开发(客户端架构 part15 of vegine)

    一个接口需要统一的派生接口,这样做的好处在于能够统一的进行管理.我所知的脚本语言中,接口有多重接口,也还有所谓的虚基类,这些都是方便类的管理.在vengine(微引擎)中,统一的的接口管理为kerne ...

随机推荐

  1. grep参数说明及常用用法

    grep参数说明及常用用法 趁着午休的时间把自己经常使用的一些grep命令整理一下. 方便以后查看. 后续会逐步把awk/sed/find等常用的命令理一理. 增强下记忆. 也算是对得起自己了. ^^ ...

  2. System Operations on AWS - Lab 6W - Using Auto Scaling (Windows)

    创建你的一个web server,然后将这个实例制成你的AMI,通过启动配置生成一个Auto Scaling组(包括scale-in/scale-out策略),配置一台Load Balancer指向你 ...

  3. 40多个非常有用的Oracle 查询语句

    给大家介绍是40多个非常有用的Oracle 查询语句,主要涵盖了日期操作,获取服务器信息,获取执行状态,计算数据库大小等等方面的查询.这些是所有Oracle 开发者都必备的技能,所以快快收藏吧! 日期 ...

  4. vim 编辑器笔记

    vim 编辑器 命令模式(默认),尾行模式 : / 两种方式 (Esc比较慢,连续连词esc,删除全部尾行内容),编辑模式 a,i,o,s :q 退出编辑不保存 :wq 保存编辑并退出 :w 保存并写 ...

  5. .NET设计模式(8):适配器模式(Adapter Pattern)

    ):适配器模式(Adapter Pattern)    适配器模式(Adapter Pattern) --.NET设计模式系列之八 Terrylee,2006年2月 概述 在软件系统中,由于应用环境的 ...

  6. OC - 18.监听iPhone的网络状态

    使用系统的方法来监听网络状态 系统的方法是通过通知机制来实现网络状态的监听 实现网络状态监听的步骤 定义Reachability类型的成员变量来保存网络的状态 @property (nonatomic ...

  7. js小分享

    之前实现一些js代码时,总觉得无法下手,所以最近在学习一下特别细的知识点,分享笔记.嘻嘻,偷个小懒,我把自己的笔记拍个照片就不打字了.嘎嘎,放心放心,自觉得字写的还算ok的啦- 表示家里的老弟玩游戏, ...

  8. POJ_3143 验证“歌德巴赫猜想”

    今天晚上的火车回家啦.所以提前更出来~.愉快的收拾我的包裹~滚回家吃半个月~胖几斤又要回学校啦~ T T这个假期虽然很忙.但是我觉得很有意义.很有价值~爱你们~ 描述 验证“歌德巴赫猜想”,即:任意一 ...

  9. 343. Integer Break -- Avota

    问题描述: Given a positive integer n, break it into the sum of at least two positive integers and maximi ...

  10. jQuery慢慢啃之ajax(九)

    1.jQuery.ajax(url,[settings])//通过 HTTP 请求加载远程数据 如果要处理$.ajax()得到的数据,则需要使用回调函数.beforeSend.error.dataFi ...