C++中的类——类的定义和声明

面向对象最大的特征就是提出了类和对象的概念。在以面向对象的方式开发应用程序时,将遇到的各种事物抽象为类,类中通常包含数据和操作数据的方法,用户通过实例化类对象来访问类中的数据和方法。


一、类的定义

class/struct 类名                        //类头

{数据方法的定义(可能含有类型成员)};        //类体


1、使用class和struct的唯一区别是:使用class定义的类在没有被强制限定的话,其成员时私有的,既不能被外部调用。使用struct的话,其成员是公共的,可以被外部调用。


2、每个类定义了唯一的类型,即使两个类的成员完全一样,只要类名不同,它们也是不同类型。


3、类体中的数据描述的是类的特征(属性),方法是类中定义的函数,描述类的行为。类型成员用于在类的作用域中指定类型的别名。

   3.1、数据

      3.1.1、C++11新标准规定,可以为数据成员提供一个类内初始值。在创建对象时,类内初始值将用于初始化数据成员,没有初始值的成员将被默认初始化。但是需要注意:类内初始值要么放在等号右边,要么放在花括号内,记住不能使用圆括号。

————————————————————————————————————————————————

   3.2、方法

      3.2.1、所有成员的声明都必须在类的内部,但是成员函数体的定义则既可以在类的内部也可以在类的外部。当定义在类的外部时函数名之前需要加上类名和作用域运算符(::)以显式的指出该函数是对应类的成员函数,并且,定义需与声明匹配。

      3.2.2、在类的外部定义成员函数时,必须同时提供类名和函数名。一旦遇到了类名,定义的剩余部分就在类的作用域之内了,这里的剩余部分包括参数列表和函数体。结果就是我们可以直接使用类的其他成员而无需再次授权了。但是函数的返回类型通常出现在类名之前,所以返回类型中使用的名字都位于类的作用域之外。如果需要使用类中的类型成员作为返回类型,则必须指明它是哪个类的成员。

            struct part

            {

               typedef double DD;

               DD fun(DD I);

            };

            part::DD part::fun(DD i){//定义}

      3.2.3、定义在类内部的函数是隐式的inline函数。可以在类的内部把inline作为声明的一部分显式的声明成员函数,也可以在类的外部用inline修饰函数的定义。无需在声明和定义的地方同时说明inline,但最好只在外部定义的地方说明内联,使程序更容易理解。(inline说明只是向编译器发出一个请求,编译器可以选择忽略这个请求

   和我们在头文件中定义inline函数的原因一样(内联函数可以在程序中多次定义,但必须完全一致),inline成员函数也应该与相应的类定义在同一个头文件中。

      3.2.4、在定义类的方法(成员函数)时,如果不需要在方法中修改类的数据成员,在方法声明和定义的参数列表后都必须同时使用const关键字,表示用户不能再该方法中修改类的数据成员,这样的成员函数称为常量成员函数(1)常量对象,以及常量对象的引用或指针都只能调用常量成员函数。(2)非常量成员函数可以调用常量成员函数,常量成员函数不能调用非常量成员函数(详情参考this指针第5点)。

   记住,这里的const是个顶层const,也就是说如果类中包含指针成员,此时这个指针就是个常量指针,不能改变指向,但可以改变所指元素的值。

   class p

   {

         int a(int a,int b) const;

   };

   int a(int a,int b) const

   {

         //不能修改类成员的值

   }

      3.2.5、有时,我们希望能修改类的某个数据成员,即使是在一个const成员函数内。可以通过在变量的声明中加入mutable关键字做到这一点。一个可变数据成员永远不会是const,即使它是const对象的成员。

      3.2.6、成员函数也可以被重载,只要满足重载的基本条件(参数数量或类型有区别)即可。

         特别的,通过区分成员函数是否是const的,可以对其进行重载。因为非常量版本的函数对于常量对象是不可用的,所以只能在一个常量对象上调用const成员函数。另一方面,虽然可以在常量对象上调用常量或非常量版本的函数,但显然此时非常量版本是一个更好的匹配。所以此时,对象是否是const的决定了应该调用哪个函数。   

      3.2.7、成员函数中使用的名字按照如下方式解析:

         (1)首先,在成员函数内查找该名字的声明。只有在函数使用之前出现的声明才会被考虑。

         (2)如果在成员函数内没有找到,则在类内继续查找,这时类的所有成员都可以被考虑。

         (3)如果类内也没有找到该名字的声明,在类定义和成员函数定义之前的作用域内继续查找。

      一般来说,最好不要使用其它成员的名字作为某个成员函数的参数。可以通过作用域运算符强制指定是哪个名字。

————————————————————————————————————————————————

   3.3、类型成员

      3.3.1、除了定义数据方法以外,类还可以自定义某种类型成员它是类型在类中的别名(使用typedef或using(C++11))。

         3.3.2、由类定义的类型名字和其他成员一样存在访问权限。

         3.3.3、类类型成员使用作用域运算符访问。

         3.3.4、用来定义类型的成员必须先定义后使用,类型成员通常出现在类开始的地方。

            (1)在类中,如果成员使用了外层作用域中的某个名字,而该名字代表一种类型,即使两次定义完全一样,也是错误的行为(这一点不同于内层作用域中的名字查找规则)。有些编译器并不会报错,而忽略代码有错的事实。

typedef char I;

struct part

{

    I a;             //I为char

    typedef int I;             //错误,不能重新定义I

    I b;

};

            (2)一般来说,内层作用域可以重新定义外层作用域中的名字,即使该名字已经在内层作用域中使用过。

int i=0;          //外层

int main()

{

   int a,b;

   a=i;              //使用外层作用域,a=i=0

   int i=1;             //内层

   b=i;               //使用内层作用域,a=i=1

}

typedef char I;

int main()

{

cout<<sizeof(I)<<endl;                  //I为char

 typedef int I;

 cout<<sizeof(I)<<endl;                //I为int

}


4、编译器分两步处理类:首先编译成员的声明,处理完所有声明后然后才轮到成员函数体。因此,成员函数体可以随意使用类中的其他成员而无须在意这些成员出现的次序。但是需要注意声明中使用的名字,包括返回类型或者参数列表中使用的名字,都必须在使用前确保可见。如果某个成员的声明使用了其声明语句之前类中尚未出现的名字,则编译器将会在类的作用域外继续查找。


5、可以在定义类的同时定义定义对象

   class p{int a;int b();}p1,p2;

   也可以先定义类,然后再定义对象。这里需要注意:与C中的结构体等对象的定义不同,C++允许把类名作为类型的名字使用而不需要之前的class或struct限定符,而C中限定符是必不可少的,它是类型名的一部分。

                 struct p{int a;int b;};

                  C++:struct p p1;或p p1;

                  C:struct p p1;


 6、使用访问说明符可以加强类的封装性:

   8.1、定义在public说明符之后的成员在整个程序内可被访问,public定义类的接口。

   8.2、定义在private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问也不能被派生类访问,private部分封装(隐藏)了类的实现细节。

   8.3、定义在protected之后的成员被称为保护成员,该成员只能在该类和该类的派生类(子类)中访问。

   8.3、访问说明符的优先级是高于使用class和struct的默认访问属性的。

   8.4、一个类可以包含任意数量的访问说明符。


二、类的声明

class 类名;


7、我们可以仅仅声明类而暂时不定义它,这种声明被称为前向声明。在它声明之后定义之前该类是个不完全类型

8、不完全类型只能在非常有限的情况下使用:可以定义指向这种类型的指针或引用,也可以作为一个已经声明(但没有定义)的函数的参数或返回类型。

9、对于一个类来说,在创建它的对象前必须首先完成类的定义,而不能仅仅被声明。否则编译器就无法了解这样的对象需要多少存储空间。类似的,类也必须首先被定义,然后才能用引用或者指针访问其成员。

10、对于类的静态成员,直到类被定义之后数据成员才能被声明成这种类类型。我们必须首先完成类的定义,然后编译器才能知道存储该数据成员需要多少空间。因为只有当类全部完成后类才算被定义,所以一个类的成员类型不能是该类自己。然而,一旦一个类的名字出现后,它就被认为是声明过了(但尚未定义),因此类允许包含指向它自身类型的引用或指针。

  • 69
    点赞
  • 293
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值