C++虚函数表分析

转自:http://blog.csdn.net/wenrenhua08/article/details/40043811#


   在<<逆向C++>>一文中提到 VC6.0 以上的编译器支持一个d1reportAllClassLayout的开关, 可以输出所有对象的内存布局信息, 我自己常用vs2005来开发,所以这里我就以vs2005为例讲怎么设置d1reportAllClassLayout。

        右键项目属性(Properties)—》配制属性(Configuration Properties)—》C/C++--》命令行(Command Line)的框里输入/d1reportAllClassLayout,即可看类的对象布局,如下图:(当然也可以使用命令行:cl –d1reportSingleClassLayout[classname] test.cpp)


测试代码:

  1. class CBase  
  2. {  
  3. public:  
  4.         virtual void fun(void) {}  
  5.   
  6. private:  
  7.         int m_valuable;  
  8. };  
class CBase
{
public:
        virtual void fun(void) {}

private:
        int m_valuable;
};
输出结果:

  1. class CBase size(8):  
  2.  +---  
  3.  0 | {vfptr}  
  4.  4 | m_valuable  
  5.  +---  
  6. CBase::$vftable@:  
  7.  | &CBase_meta  
  8.  |  0  
  9.  0 | &CBase::fun  
  10. CBase::fun this adjustor: 0  
class CBase size(8):
 +---
 0 | {vfptr}
 4 | m_valuable
 +---
CBase::$vftable@:
 | &CBase_meta
 |  0
 0 | &CBase::fun
CBase::fun this adjustor: 0
  1. CDerived:非virtual继承CBase,持有一个virtual重写方法和一个virtual新方法,一个成员变量  
  2. class CDerived: public CBase  
  3. {  
  4. public:  
  5.     void fun(void) { }  
  6.     virtual void vfun(void) { }  
  7.   
  8. public:  
  9.     int m_derived;  
  10. };  
  11. 编译后输出结果:  
  12. class CDerived size(12):  
  13.  +---  
  14.  | +--- (base class CBase)  
  15.  0 | | {vfptr}  
  16.  4 | | m_valuable  
  17.  | +---  
  18.  8 | m_derived  
  19.  +---  
  20. CDerived::$vftable@:  
  21.  | &CDerived_meta  
  22.  |  0  
  23.  0 | &CDerived::fun  
  24.  1 | &CDerived::vfun  
  25. CDerived::fun this adjustor: 0  
  26. CDerived::vfun this adjustor: 0  
  27. 其中vftable@CBase的CBase::fun项在这里更新为CDerived::fun,同时增加了一项CDerived::vfun。  
  28. CDerived2:virtual继承CBase,持有一个virtual重写方法和一个virtual新方法,一个成员变量,因此结构为vftable@自身,vbtable@自身,member@自身,以及CBase结构。  
  29. 总结:  
  30. class CDerived2: virtual public CBase  
  31. {  
  32. public:  
  33.     void fun(void) { }  
  34.     virtual void vfun(void) { }  
  35.   
  36. public:  
  37.     int m_derived;  
  38. };  
  39. 结果输出:  
  40. class CDerived2 size(20):  
  41.  +---  
  42.  0 | {vfptr}  
  43.  4 | {vbptr}  
  44.  8 | m_derived  
  45.  +---  
  46.  +--- (virtual base CBase)  
  47. 12 | {vfptr}  
  48. 16 | m_valuable  
  49.  +---  
  50. CDerived2::$vftable@CDerived2@:  
  51.  | &CDerived2_meta  
  52.  |  0  
  53.  0 | &CDerived2::vfun  
  54. CDerived2::$vbtable@:  
  55.  0 | -4  
  56.  1 | 8 (CDerived2d(CDerived2+4)CBase)  
  57. CDerived2::$vftable@CBase@:  
  58.  | -12  
  59.  0 | &CDerived2::fun  
  60. CDerived2::fun this adjustor: 12  
  61. CDerived2::vfun this adjustor: 0  
  62. vbi:    class  offset o.vbptr  o.vbte fVtorDisp  
  63.            CBase      12       4       4 0  
  64. 其中vftable@自身只有一项:CDerived2::vfun(),vbtable@自身只有一项:它virtual继承的父类CBase,而vftable@CBase原来的CBase::fun更新为CDerived2::fun。  
  65.   
  66. CDerived3:virtual继承CBase,因此结构为vbtable@自身,member@自身,CBase结构  
  67. class CDerived3: virtual public CBase  
  68. {  
  69. public:  
  70.     void fun(void) { }  
  71.   
  72. public:  
  73.     int m_derived3;  
  74. };  
  75. 结果输出:  
  76. class CDerived3 size(16):  
  77.  +---  
  78.  0 | {vbptr}  
  79.  4 | m_derived3  
  80.  +---  
  81.  +--- (virtual base CBase)  
  82.  8 | {vfptr}  
  83. 12 | m_valuable  
  84.  +---  
  85. CDerived3::$vbtable@:  
  86.  0 | 0  
  87.  1 | 8 (CDerived3d(CDerived3+0)CBase)  
  88. CDerived3::$vftable@:  
  89.  | -8  
  90.  0 | &CDerived3::fun  
  91. CDerived3::fun this adjustor: 8  
  92. vbi:    class  offset o.vbptr  o.vbte fVtorDisp  
  93.            CBase       8       0       4 0  
  94. CGDerived:继承CDerived2、CDerived3  
  95. class CGDerived: public CDerived2, public CDerived3  
  96. {  
  97. public:  
  98.     void vfun() { }  
  99.     virtual void vgfun() { }  
  100.   
  101. public:  
  102.     int m_gd;  
  103. };  
  104. 输出:  
  105. class CGDerived size(32):  
  106.  +---  
  107.  | +--- (base class CDerived2)  
  108.  0 | | {vfptr}  
  109.  4 | | {vbptr}  
  110.  8 | | m_derived  
  111.  | +---  
  112.  | +--- (base class CDerived3)  
  113. 12 | | {vbptr}  
  114. 16 | | m_derived3  
  115.  | +---  
  116. 20 | m_gd  
  117.  +---  
  118.  +--- (virtual base CBase)  
  119. 24 | {vfptr}  
  120. 28 | m_valuable  
  121.  +---  
  122. CGDerived::$vftable@CDerived2@:  
  123.  | &CGDerived_meta  
  124.  |  0  
  125.  0 | &CGDerived::vfun  
  126.  1 | &CGDerived::vgfun  
  127. CGDerived::$vbtable@CDerived2@:  
  128.  0 | -4  
  129.  1 | 20 (CGDerivedd(CDerived2+4)CBase)  
  130. CGDerived::$vbtable@CDerived3@:  
  131.  0 | 0  
  132.  1 | 12 (CGDerivedd(CDerived3+0)CBase)  
  133. CGDerived::$vftable@CBase@:  
  134.  | -24  
  135.  0 | &thunk: this-=12; goto CDerived2::fun  
  136. CGDerived::vfun this adjustor: 0  
  137. CGDerived::vgfun this adjustor: 0  
  138. vbi:    class  offset o.vbptr  o.vbte fVtorDisp  
  139.            CBase      24       4       4 0  
  140. 因此首先是CDerived2的结构和CDerived3的结构,自己的新virtual方法vgfun则添加在最左父类CDerived2的虚函数表中。然后是自己的成员。最后,CDerived2和CDerived3的父类CBase结构也带入其中。它的fun默认指向CGDerived的最左父类CDerived2::fun。  
  141.   
  142. CGG:继承CGDerived  
  143. class CGG: public CGDerived  
  144. {  
  145. public:  
  146.     int m_kc;  
  147. };  
  148. 输出:  
  149. class CGG size(36):  
  150.  +---  
  151.  | +--- (base class CGDerived)  
  152.  | | +--- (base class CDerived2)  
  153.  0 | | | {vfptr}  
  154.  4 | | | {vbptr}  
  155.  8 | | | m_derived  
  156.  | | +---  
  157.  | | +--- (base class CDerived3)  
  158. 12 | | | {vbptr}  
  159. 16 | | | m_derived3  
  160.  | | +---  
  161. 20 | | m_gd  
  162.  | +---  
  163. 24 | m_kc  
  164.  +---  
  165.  +--- (virtual base CBase)  
  166. 28 | {vfptr}  
  167. 32 | m_valuable  
  168.  +---  
  169. CGG::$vftable@CDerived2@:  
  170.  | &CGG_meta  
  171.  |  0  
  172.  0 | &CGDerived::vfun  
  173.  1 | &CGDerived::vgfun  
  174. CGG::$vbtable@CDerived2@:  
  175.  0 | -4  
  176.  1 | 24 (CGGd(CDerived2+4)CBase)  
  177. CGG::$vbtable@CDerived3@:  
  178.  0 | 0  
  179.  1 | 16 (CGGd(CDerived3+0)CBase)  
  180. CGG::$vftable@CBase@:  
  181.  | -28  
  182.  0 | &thunk: this-=16; goto CDerived2::fun  
  183. vbi:    class  offset o.vbptr  o.vbte fVtorDisp  
  184.            CBase      28       4       4 0  
  185. 增加一个变量,基本只是把CGDerived的结构再套一层,最后加上自己的成员变量。vbtable所指向的父类结构依然在最后。  
  186.   
  187. 空类  
  188. class CBase2  
  189. {  
  190.   
  191. };  
  192. 输出:  
  193. class CBase2 size(1):  
  194.  +---  
  195.  +---  
  196. CD2:virtual继承则一定会创建vbtable,用vbptr指针指向,因此size为4  
  197. class CD2: virtual public CBase2  
  198. {  
  199.   
  200. };  
  201. 输出:  
  202. class CD2 size(4):  
  203.  +---  
  204.  0 | {vbptr}  
  205.  +---  
  206.  +--- (virtual base CBase2)  
  207.  +---  
  208. CD2::$vbtable@:  
  209.  0 | 0  
  210.  1 | 4 (CD2d(CD2+0)CBase2)  
  211. vbi:    class  offset o.vbptr  o.vbte fVtorDisp  
  212.           CBase2       4       0       4 0  
  213.   
  214. CE:非virtual继承CD2和CDerived2,于是按照类的声明顺序,先带入CDerived2的结构,再带入CD2的结构(而不是按继承顺序)  
  215. class CE: public CD2, public CDerived2  
  216. {  
  217.   
  218. };  
  219. 输出:  
  220. class CE size(24):  
  221.  +---  
  222.  | +--- (base class CDerived2)  
  223.  0 | | {vfptr}  
  224.  4 | | {vbptr}  
  225.  8 | | m_derived  
  226.  | +---  
  227.  | +--- (base class CD2)  
  228. 12 | | {vbptr}  
  229.  | +---  
  230.  +---  
  231.  +--- (virtual base CBase2)  
  232.  +---  
  233.  +--- (virtual base CBase)  
  234. 16 | {vfptr}  
  235. 20 | m_valuable  
  236.  +---  
  237. CE::$vftable@CDerived2@:  
  238.  | &CE_meta  
  239.  |  0  
  240.  0 | &CDerived2::vfun  
  241. CE::$vbtable@CD2@:  
  242.  0 | 0  
  243.  1 | 4 (CEd(CD2+0)CBase2)  
  244.  2 | 4 (CEd(CE+12)CBase)  
  245. CE::$vbtable@CDerived2@:  
  246.  0 | -4  
  247.  1 | 12 (CEd(CDerived2+4)CBase)  
  248. CE::$vftable@CBase@:  
  249.  | -16  
  250.  0 | &thunk: this-=4; goto CDerived2::fun  
  251. vbi:    class  offset o.vbptr  o.vbte fVtorDisp  
  252.           CBase2      16      12       4 0  
  253.            CBase      16      12       8 0  
  254. CF:virtual继承CBase和CBase2,vbtable此时的项便有两个,此时按照继承的顺序,而不是按照类的声明顺序  
  255. class CF: virtual public CBase2, virtual public CBase  
  256. {  
  257.   
  258. };  
  259. 输出:  
  260. class CF size(12):  
  261.  +---  
  262.  0 | {vbptr}  
  263.  +---  
  264.  +--- (virtual base CBase2)  
  265.  +---  
  266.  +--- (virtual base CBase)  
  267.  4 | {vfptr}  
  268.  8 | m_valuable  
  269.  +---  
  270. CF::$vbtable@:  
  271.  0 | 0  
  272.  1 | 4 (CFd(CF+0)CBase2)  
  273.  2 | 4 (CFd(CF+0)CBase)  
  274. CF::$vftable@:  
  275.  | -4  
  276.  0 | &CBase::fun  
  277. vbi:    class  offset o.vbptr  o.vbte fVtorDisp  
  278.           CBase2       4       0       4 0  
  279.            CBase       4       0       8 0  
CDerived:非virtual继承CBase,持有一个virtual重写方法和一个virtual新方法,一个成员变量
class CDerived: public CBase
{
public:
	void fun(void) { }
	virtual void vfun(void) { }

public:
	int m_derived;
};
编译后输出结果:
class CDerived size(12):
 +---
 | +--- (base class CBase)
 0 | | {vfptr}
 4 | | m_valuable
 | +---
 8 | m_derived
 +---
CDerived::$vftable@:
 | &CDerived_meta
 |  0
 0 | &CDerived::fun
 1 | &CDerived::vfun
CDerived::fun this adjustor: 0
CDerived::vfun this adjustor: 0
其中vftable@CBase的CBase::fun项在这里更新为CDerived::fun,同时增加了一项CDerived::vfun。
CDerived2:virtual继承CBase,持有一个virtual重写方法和一个virtual新方法,一个成员变量,因此结构为vftable@自身,vbtable@自身,member@自身,以及CBase结构。
总结:
class CDerived2: virtual public CBase
{
public:
	void fun(void) { }
	virtual void vfun(void) { }

public:
	int m_derived;
};
结果输出:
class CDerived2 size(20):
 +---
 0 | {vfptr}
 4 | {vbptr}
 8 | m_derived
 +---
 +--- (virtual base CBase)
12 | {vfptr}
16 | m_valuable
 +---
CDerived2::$vftable@CDerived2@:
 | &CDerived2_meta
 |  0
 0 | &CDerived2::vfun
CDerived2::$vbtable@:
 0 | -4
 1 | 8 (CDerived2d(CDerived2+4)CBase)
CDerived2::$vftable@CBase@:
 | -12
 0 | &CDerived2::fun
CDerived2::fun this adjustor: 12
CDerived2::vfun this adjustor: 0
vbi:    class  offset o.vbptr  o.vbte fVtorDisp
           CBase      12       4       4 0
其中vftable@自身只有一项:CDerived2::vfun(),vbtable@自身只有一项:它virtual继承的父类CBase,而vftable@CBase原来的CBase::fun更新为CDerived2::fun。

CDerived3:virtual继承CBase,因此结构为vbtable@自身,member@自身,CBase结构
class CDerived3: virtual public CBase
{
public:
	void fun(void) { }

public:
	int m_derived3;
};
结果输出:
class CDerived3 size(16):
 +---
 0 | {vbptr}
 4 | m_derived3
 +---
 +--- (virtual base CBase)
 8 | {vfptr}
12 | m_valuable
 +---
CDerived3::$vbtable@:
 0 | 0
 1 | 8 (CDerived3d(CDerived3+0)CBase)
CDerived3::$vftable@:
 | -8
 0 | &CDerived3::fun
CDerived3::fun this adjustor: 8
vbi:    class  offset o.vbptr  o.vbte fVtorDisp
           CBase       8       0       4 0
CGDerived:继承CDerived2、CDerived3
class CGDerived: public CDerived2, public CDerived3
{
public:
	void vfun() { }
	virtual void vgfun() { }

public:
	int m_gd;
};
输出:
class CGDerived size(32):
 +---
 | +--- (base class CDerived2)
 0 | | {vfptr}
 4 | | {vbptr}
 8 | | m_derived
 | +---
 | +--- (base class CDerived3)
12 | | {vbptr}
16 | | m_derived3
 | +---
20 | m_gd
 +---
 +--- (virtual base CBase)
24 | {vfptr}
28 | m_valuable
 +---
CGDerived::$vftable@CDerived2@:
 | &CGDerived_meta
 |  0
 0 | &CGDerived::vfun
 1 | &CGDerived::vgfun
CGDerived::$vbtable@CDerived2@:
 0 | -4
 1 | 20 (CGDerivedd(CDerived2+4)CBase)
CGDerived::$vbtable@CDerived3@:
 0 | 0
 1 | 12 (CGDerivedd(CDerived3+0)CBase)
CGDerived::$vftable@CBase@:
 | -24
 0 | &thunk: this-=12; goto CDerived2::fun
CGDerived::vfun this adjustor: 0
CGDerived::vgfun this adjustor: 0
vbi:    class  offset o.vbptr  o.vbte fVtorDisp
           CBase      24       4       4 0
因此首先是CDerived2的结构和CDerived3的结构,自己的新virtual方法vgfun则添加在最左父类CDerived2的虚函数表中。然后是自己的成员。最后,CDerived2和CDerived3的父类CBase结构也带入其中。它的fun默认指向CGDerived的最左父类CDerived2::fun。

CGG:继承CGDerived
class CGG: public CGDerived
{
public:
	int m_kc;
};
输出:
class CGG size(36):
 +---
 | +--- (base class CGDerived)
 | | +--- (base class CDerived2)
 0 | | | {vfptr}
 4 | | | {vbptr}
 8 | | | m_derived
 | | +---
 | | +--- (base class CDerived3)
12 | | | {vbptr}
16 | | | m_derived3
 | | +---
20 | | m_gd
 | +---
24 | m_kc
 +---
 +--- (virtual base CBase)
28 | {vfptr}
32 | m_valuable
 +---
CGG::$vftable@CDerived2@:
 | &CGG_meta
 |  0
 0 | &CGDerived::vfun
 1 | &CGDerived::vgfun
CGG::$vbtable@CDerived2@:
 0 | -4
 1 | 24 (CGGd(CDerived2+4)CBase)
CGG::$vbtable@CDerived3@:
 0 | 0
 1 | 16 (CGGd(CDerived3+0)CBase)
CGG::$vftable@CBase@:
 | -28
 0 | &thunk: this-=16; goto CDerived2::fun
vbi:    class  offset o.vbptr  o.vbte fVtorDisp
           CBase      28       4       4 0
增加一个变量,基本只是把CGDerived的结构再套一层,最后加上自己的成员变量。vbtable所指向的父类结构依然在最后。

空类
class CBase2
{

};
输出:
class CBase2 size(1):
 +---
 +---
CD2:virtual继承则一定会创建vbtable,用vbptr指针指向,因此size为4
class CD2: virtual public CBase2
{

};
输出:
class CD2 size(4):
 +---
 0 | {vbptr}
 +---
 +--- (virtual base CBase2)
 +---
CD2::$vbtable@:
 0 | 0
 1 | 4 (CD2d(CD2+0)CBase2)
vbi:    class  offset o.vbptr  o.vbte fVtorDisp
          CBase2       4       0       4 0

CE:非virtual继承CD2和CDerived2,于是按照类的声明顺序,先带入CDerived2的结构,再带入CD2的结构(而不是按继承顺序)
class CE: public CD2, public CDerived2
{

};
输出:
class CE size(24):
 +---
 | +--- (base class CDerived2)
 0 | | {vfptr}
 4 | | {vbptr}
 8 | | m_derived
 | +---
 | +--- (base class CD2)
12 | | {vbptr}
 | +---
 +---
 +--- (virtual base CBase2)
 +---
 +--- (virtual base CBase)
16 | {vfptr}
20 | m_valuable
 +---
CE::$vftable@CDerived2@:
 | &CE_meta
 |  0
 0 | &CDerived2::vfun
CE::$vbtable@CD2@:
 0 | 0
 1 | 4 (CEd(CD2+0)CBase2)
 2 | 4 (CEd(CE+12)CBase)
CE::$vbtable@CDerived2@:
 0 | -4
 1 | 12 (CEd(CDerived2+4)CBase)
CE::$vftable@CBase@:
 | -16
 0 | &thunk: this-=4; goto CDerived2::fun
vbi:    class  offset o.vbptr  o.vbte fVtorDisp
          CBase2      16      12       4 0
           CBase      16      12       8 0
CF:virtual继承CBase和CBase2,vbtable此时的项便有两个,此时按照继承的顺序,而不是按照类的声明顺序
class CF: virtual public CBase2, virtual public CBase
{

};
输出:
class CF size(12):
 +---
 0 | {vbptr}
 +---
 +--- (virtual base CBase2)
 +---
 +--- (virtual base CBase)
 4 | {vfptr}
 8 | m_valuable
 +---
CF::$vbtable@:
 0 | 0
 1 | 4 (CFd(CF+0)CBase2)
 2 | 4 (CFd(CF+0)CBase)
CF::$vftable@:
 | -4
 0 | &CBase::fun
vbi:    class  offset o.vbptr  o.vbte fVtorDisp
          CBase2       4       0       4 0
           CBase       4       0       8 0

总结:

 继承方式:非virtual继承:导入各个父类的结构(按照父类声明的顺序,从上到下),自身member在最后

         重写virtual方法:更新该方法最早定义的类的vftable

        新的virtual方法:在最左父类的vftable增加

 继承方式:有virtual继承:在自身member后增加virtual父类的结构(按照子类继承的顺序从左到右),同时在最前面增加vbtable(如果没有的话),增加一项指向父类结构

         重写virtual方法:更新该方法的最早定义的类的vftable

         新的virtual方法:在自身最前面增加vftable(如果没有的话),在自己的vftable增加


附 所有源码:

  1. #ifndef TEST_CBASE_H   
  2. #define TEST_CBASE_H   
  3.   
  4. class CBase  
  5. {  
  6. public:  
  7.     CBase();  
  8.     explicit CBase(int valuabel);  
  9.     ~CBase();  
  10.   
  11.     virtual void fun(void) {}  
  12.   
  13. private:  
  14.     int m_valuable;  
  15. };  
  16.   
  17. class CDerived: public CBase  
  18. {  
  19. public:  
  20.     void fun(void) { }  
  21.     virtual void vfun(void) { }  
  22.   
  23. public:  
  24.     int m_derived;  
  25. };  
  26.   
  27. class CDerived2: virtual public CBase  
  28. {  
  29. public:  
  30.     void fun(void) { }  
  31.     virtual void vfun(void) { }  
  32.   
  33. public:  
  34.     int m_derived;  
  35. };  
  36.   
  37. class CDerived3: virtual public CBase  
  38. {  
  39. public:  
  40.     void fun(void) { }  
  41.   
  42. public:  
  43.     int m_derived3;  
  44. };  
  45.   
  46. class CGDerived: public CDerived2, public CDerived3  
  47. {  
  48. public:  
  49.     void vfun() { }  
  50.     virtual void vgfun() { }  
  51.   
  52. public:  
  53.     int m_gd;  
  54. };  
  55.   
  56. class CGG: public CGDerived  
  57. {  
  58. public:  
  59.     int m_kc;  
  60. };  
  61.   
  62.   
  63. class CBase2  
  64. {  
  65.   
  66. };  
  67.   
  68. class CD2: virtual public CBase2  
  69. {  
  70.   
  71. };  
  72.   
  73. class CE: public CD2, public CDerived2  
  74. {  
  75.   
  76. };  
  77.   
  78. class CF: virtual public CBase2, virtual public CBase  
  79. {  
  80.   
  81. };  
  82.   
  83.   
  84. #endif//TEST_CBASE_H  
#ifndef TEST_CBASE_H
#define TEST_CBASE_H

class CBase
{
public:
	CBase();
	explicit CBase(int valuabel);
	~CBase();

	virtual void fun(void) {}

private:
	int m_valuable;
};

class CDerived: public CBase
{
public:
	void fun(void) { }
	virtual void vfun(void) { }

public:
	int m_derived;
};

class CDerived2: virtual public CBase
{
public:
	void fun(void) { }
	virtual void vfun(void) { }

public:
	int m_derived;
};

class CDerived3: virtual public CBase
{
public:
	void fun(void) { }

public:
	int m_derived3;
};

class CGDerived: public CDerived2, public CDerived3
{
public:
	void vfun() { }
	virtual void vgfun() { }

public:
	int m_gd;
};

class CGG: public CGDerived
{
public:
	int m_kc;
};


class CBase2
{

};

class CD2: virtual public CBase2
{

};

class CE: public CD2, public CDerived2
{

};

class CF: virtual public CBase2, virtual public CBase
{

};


#endif//TEST_CBASE_H



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值