首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

C++中的inline函数的实现部分应该放在哪里呢?解决方案

2012-03-11 
C++中的inline函数的实现部分应该放在哪里呢?C++中的inline函数的实现部分到底该放在哪里呢?C++中的类中in

C++中的inline函数的实现部分应该放在哪里呢?
C++中的inline函数的实现部分到底该放在哪里呢?

C++中的类中inline函数的实现部分究竟放在哪里?   下面是两位专家的说法:
下面引自林锐博士的《高质量C++编程》P67


定义在类声明之中的成员函数将自动地成为内联函数,例如
class   A
{
public:
    void   Foo(int   x,int   y);{       }         //   自动地成为内联函数  
}

将成员函数的定义体放在类声明之中虽然能带来书写上的方便,但不是一种良好的编程风格,上例应该改成:
//   头文件:
class   A
{
public:
      void   Foo(int   x,   int   y);
}

//   定义头文件
inline   void   A::Foo(int   x,   int   y)
{

}


C++的发明者Bjarne   Stroustrup博士在他所著的书《C++语言的设计和演化》中则是这样论述这个问题(见《C++语言的设计和演化》P12):
在带类的C中只有成员函数能做成在线(注:也就是设计为inline函数)的,而要求函数成为在线只有一种方式,那就是把它的放进类的声明之中。例如:
class     stack
{
/*   …   /*
char   pop()
{
If(top <=min)   error(“stack   underflow”);
    return   *--top;
}
};
事实上,那时也看到这会使类的声明显得比较杂乱。另一方面,这看起来也是个好东西,因为它不鼓励在线函数的过度使用。关键字inline和允许在线成员函数的功能都是后来由C++提供的。例如,在C++中可以写下面这样的代码:
class     stack
{
/*   …   /*
char   pop();
};

Inline   char   stack::   pop()
{
If(top <=min)   error(“stack   underflow”);
    return   *--top;
}

      照两位专家的说法,inline函数的实现代码似乎既可以放在.h文件,也可以放在.cpp文件。实际上是不是这样呢?我使用VC6.0做了一个测试程序(Win32控制台程序):
程序运行环境:英文版Win   Xp   sp2
程序编译环境:VC++   6.0
首先我把inline函数的实现代码可以放在.h文件
测试程序如下:
//   MyString.h
#ifndef   MY_STRING_H
#define   MY_STRING_H

#include   <string.h>

class   CMyString
{
private:
char   *pszData;
public:
        CMyString();
        CMyString(char   *psz);
  int   GetLength()
  {
  return   strlen(pszData);
  }
~CMyString();
};

#endif
#endif

//   MyString.cpp

#include   "stdafx.h "
#include   "MyString.h "
#include   <iostream.h>

CMyString::CMyString()
{
      pszData   =   new   char[20];
}

CMyString::CMyString(char   *psz)
{
        pszData   =   new   char[20];
strcpy(pszData,psz);
}

CMyString::~CMyString()
{
delete   []pszData;
        pszData   =   NULL;
}


//   TestString.cpp

#include   "stdafx.h "
#include   "MyString.h "
#include   <iostream.h>

int   main(int   argc,   char*   argv[])
{
CMyString   str( "Hello   World! ");
  int   strlen   =   str.GetLength();
  cout < <strlen < <endl;
return   0;
}

程序编译运行成功。

现在我把inline函数的实现代码可以放在.cpp文件(主要修改了MyString.h和MyString.cpp)
//   MyString.h
#ifndef   MY_STRING_H
#define   MY_STRING_H

#include   <string.h>

class   CMyString
{
private:
char   *pszData;
public:
        CMyString();
        CMyString(char   *psz);
  int   GetLength();
~CMyString();
};



#endif

//   MyString.cpp

#include   "stdafx.h "
#include   "MyString.h "
#include   <iostream.h>

CMyString::CMyString()
{
      pszData   =   new   char[20];
}

CMyString::CMyString(char   *psz)
{
        pszData   =   new   char[20];
strcpy(pszData,psz);
}

inline   int   CMyString::GetLength()
{
return   strlen(pszData);
}


CMyString::~CMyString()
{
delete   []pszData;
        pszData   =   NULL;
}

//   TestString.cpp
#include   "stdafx.h "
#include   "MyString.h "
#include   <iostream.h>

int   main(int   argc,   char*   argv[])
{
CMyString   str( "Hello   World! ");
  int   strlen   =   str.GetLength();
  cout < <strlen < <endl;
return   0;
}

程序编译不出错,但是运行出错,错误信息如下:
TestString.cpp
Generating   Code...
Linking...
TestString.obj   :   error   LNK2001:   unresolved   external   symbol   "public:   int   __thiscall   CMyString::GetLength(void) "   (?GetLength@CMyString@@QAEHXZ)
Debug/TestString.exe   :   fatal   error   LNK1120:   1   unresolved   externals
Error   executing   link.exe.

TestString.exe   -   2   error(s),   0   warning(s)

值得注意的是假如我在类CMyString添加一个成员函数GetInfo()。将程序改为

//   MyString.h
#ifndef   MY_STRING_H
#define   MY_STRING_H

#include   <string.h>

class   CMyString
{
private:
char   *pszData;
public:
        CMyString();
        CMyString(char   *psz);
  int   GetLength();
void   GetInfo();
~CMyString();
};

#endif
//   MyString.cpp
#include   "stdafx.h "
#include   "MyString.h "
#include   <iostream.h>

CMyString::CMyString()
{
      pszData   =   new   char[20];
}

CMyString::CMyString(char   *psz)
{
        pszData   =   new   char[20];
strcpy(pszData,psz);
}

inline   int   CMyString::GetLength()
{
return   strlen(pszData);
}

void   CMyString::GetInfo()
{
int   strlen   =   GetLength();
cout < <strlen < <endl;
}

CMyString::~CMyString()
{
delete   []pszData;
        pszData   =   NULL;
}

//   TestString.cpp

#include   "stdafx.h "
#include   "MyString.h "
#include   <iostream.h>

int   main(int   argc,   char*   argv[])
{
CMyString   str( "Hello   World! ");
  int   strlen   =   str.GetLength();
  cout < <strlen < <endl;
return   0;
}

在这种情况下即使把inline函数的实现代码可以放在.cpp文件,程序依然能运行成功。这个我实在搞不懂了。我想这是不是VC6.0对C++标准的一个不兼容的地方呢?


[解决办法]
放在头文件


[解决办法]
放在cpp里也可以,但是这时要是有外部程序尝试访问该内联成员函数,将会联接错误,因为内联函数没有实际函数体,因此也不会存在于目标文件的导出符号表里。
这种情况就只能通过文件包含的方式引用内联函数体,所以通常内联函数都是写在.h里的

[解决办法]
jixingzhong(瞌睡虫·星辰) ( ) 信誉:102 Blog 2007-02-11 09:52:32 得分: 0


inline 函数应当和它的声明 是同一个文件的


-----------------------------------

没这种说法,虽然习惯上如此。

只要你愿意,定义和声明写在多个.h文件也没问题,只要使用者最终都包含它们就行了。

对于不会被外界使用函数,比如私有(不能有friend,或者就算有也不可能用到这些函数),
写在.cpp里也可以,不过没多少必要……

[解决办法]
我概括过inline函数的一条基本原则(不知道别人有没有类似提法):

首先介绍一个概念,“编译单元”,用不太严谨的方式定义,就是
当你把一个源文件(.cpp .cxx等)做完预处理,也就是把包含的头文件的内容全部放
到这个文件里来,所有宏都展开,等等,形成的一个逻辑上的实体——就是编译单元
一个编译单元可以单独编译,但不能链接成一个可执行程序(除非程序只有这个编译单元)

有了编译单元的概念以后,你只要确保以下这个原则就可以了:
如果在这个编译单元里使用了一个Inline函数,那么我在这个编译单元结束之前,
必须能够“看到”这个编译单元的完整定义(所有实现代码)

另外要注意,在编译单元之内,调用inline函数的代码行之前,至少要放置
一个这个inline函数的声明,当然有定义也可以

从这个原则出发,最简单的使用Inline函数的方法就是在头文件定义,
否则你要在每一个使用inline函数的编译单元里一一定义这个函数,
如果有n个编译单元,你就要把inline函数的代码重复书写n次


[解决办法]
inline 这个关键字并没有必要一定不生成函数体.
大可以生产函数体,又inline.因为这没有冲突.

我估计都是static默认链接说法这个比较合理.
改成:

inline extern int CMyString::GetLength()
{
return strlen(pszData);
}



[解决办法]
whoho 的 principle 是正确的..提一个常见的组织方法

// defs.h
#ifndef DEFS_H
#define DEFS_H

inline void inline_func ();

#include "defs.icc "

#endif // DEFS_H

// defs.icc

void inline_func ()
{
} // 实现放在这个.icc 文件中。这个文件不直接被编译。

热点排行