实用经验 64 struct和class到底什么关系?

class是C++相对于C新引入的重要特征。从C++的最初名称“C witch class”,我们可看出class在C++语言中的重要地位。在C++中,在大多数情况下,我们通过class定义用户数据类型。但不要忘了作为与C语言兼容的一种扩展型语言,C++肯定会支持C语言的struct数据结构。

在C语言中,struct的定义:struct是一种自定义的数据类型。它由若干成员构成。每个成员可是一个基础的数据类型,也可是一个用户自定义的数据类型。struct的定义形式为:

struct 结构体名称
{
	成员表列
}变量表列;

所以,从定义我们可看出struct是一种数据类型,那肯定就不能定义函数方法了。因此,在C语言中,我们不能为struct定义任何的函数方法,否则编译时会报出错误。

但是,在C++语言框架中一切都变了。在C语言中为struct定义函数成员将不被允许,而在C++中你可以随意为struct定义函数成员。所以,我们可以看出struct在两种语言中的差异。在C++中struct被看做为一个对象,你可以为它定义函数成员,构造函数和析构函数,同样可以继承。但在C中,它仅仅是一种数据结构,只能在struct中定义数据成员,而不能定义函数成员。

说到这儿,你不免有些疑惑。在C++中struct和class不是一样了吗?是的,他们确实已经很接近了。基本上没有什么根本性的差异了。其主要差别表现在初始化方式,默认访问权限和默认继承方式。下面我们就分别讨论一下。

1.关于大括号初始化

class和struct如果定义了构造函数的话,都不能用大括号进行初始化。如果没有定义构造函数,struct可以用大括号初始化。如果没有定义构造函数,且所有成员变量全是public的话,则class可以用大括号初始化。

// 声明一个二维点结构
typedef struct tagPointA
{
     int iX;
     int iY;
}PointA;
PointA pta = {1, 1}; // 可通过编译

// 声明一个二维点结构
typedef struct tagPointB
{
     int iX;
     int iY;
     tagPointB(int ix, int iy)
     :iX(ix), iY(iy)
     {}
}PointB;
PointB ptb = {1, 2}; // 不能通过编译

// 声明一个二维点类
class CPointC
{
public:
     int iX;
     int iY;
};
CPointC ptc = {1, 1}; // 可通过编译

// 声明一个二维点类
class CPointD
{
public:
     CPointD(int ix, int iy)
     :iX(ix), iY(iy)
     {}
     int iX;
     int iY; 
};
CPointD ptd = {1, 1}; // 不可通过编译

// 声明一个二维点类
class CPointE
{
public:
     CPointE(int ix, int iy)
     :iX(ix), iY(iy)
     {}
     int iX;
     int iY; 
};
CPointE pte = {1, 1}; // 不可通过编译

一般,在VC编译上编译上述代码,编译器会抛出下述错误:

error C2552: “ptb”: 不能用初始值设定项列表初始化非聚合
error C2552: “ptd”: 不能用初始值设定项列表初始化非聚合
error C2552: “pte”: 不能用初始值设定项列表初始化非聚合

最佳实践

  • 在C++中,虽struct可定义函数成员了。但我还是建议如果你定义的struct含义函数成员,请将此struct实现改成class实现。以避免你采用大括号方式初始化此对象。
  • 反过来也一样,如果你定义的class只含义数据成员,而不包含任何函数成员。请将此class实现修改成struct实现。这样你可以通过大括号的形式初始化此对象。
  • 尽量以C方式使用struct。而不要以C++方式使用struct。

2.默认访问权限

默认访问控制是struct和class最本质的一个区别,struct作为数据结构的实现体,它默认的访问权限是public,而class默认访问控制是private的。来看下面的代码:

// 定义一个复数结构体
typedef struct tagComplexA
{
    float   fReal;   		// 实部
    float   fImagin; 		// 虚部
}ComplexA;

// 定义一个复数结构体
class ComplexB
{
    float   fReal;   		// 实部
    float   fImagin; 		// 虚部
};

ComplexA comA = {1,1}; 	// 可以编译
ComplexB comB = {1,1};	// 不可编译

在VC编译中,编译上述代码。编译会抛出如下异常:

error C2552: “comB”: 不能用初始值设定项列表初始化非聚合

3.默认继承方式

class继承默认是private继承,而struct继承默认是public继承。另外class可继承于struct,struct同样可继承于class。看下面关于继承的例子:

// 类T1
class T1
{
public:
	void f()
	{
		cout<<"T1::f()"<<endl;
	}
	int x,y;
}; 	

// 类T2
struct T2
{
   int x;
   void f(){cout<<"T2::f()"<<endl;}
};

// 类TT1,派生于T1
struct TT1 : T1
{
};

// 类TT2,派生于T2
class TT2 : T2
{
};

int main()
{ 
	TT1 t1;
	TT2 t2;
	t1.f();
	t2.f();
}

将上述代码在VC编译器上编译,编译器抛出如下异常:

error C2247: “T2::f”不可访问,因为“TT2”使用“private”从“T2”继承

关于默认继承:在继承过程中,public继承还是private继承,取决于子类而不是基类。无论是class继承于struct,还是struct继承于class。
混合继承的例子:

struct A{}class B : A{};   //private继承
struct C: B{};   //public继承

4.模版方面的差异

模版应用也是class和struct的一个重要差异。在模版中,类型参数前面可以使用class或typename。如果使用struct则含义就变了。struct后面跟着的是“非类型模版参数”,而class或typename后面跟的是类型参数。看下面这个例子:

template <struct X>
void f(X x)  // 错误信息: error C2065: 'X' : undeclared identifier
{
}

而如果将struct替换成class,则可正常编译。

template <class X>
void f(X x)  // 可正常编译
{
}

通过以上的对比分析,可看出class和struct之间的差别其实还是很小的。只是在某些细节上存在差异。在使用过程中基本上可以等同看待,如我们可以像class一样为struct定义构造函数和析构函数。虽然class和struct基本上可以等同看待,但本人并不推荐这样使用它们。我建议struct还是采用C语言那种方式使用之,把它当做纯粹struct而不当作class使用。

请谨记

  • 在C++中,虽然struct和class差别很小。可等同看待。但我更建议struct还是当做数据结构使用,而不当做class对象使用。如果你想把struct作对象使用,笔者建议用class替代。
  • 从struct到class的最大区别是编程思想变化的体现。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值