从结构struct谈到类class

深入理解struct

 在C语言中,我们通常使用struct来表示不同数据类型的结合。当然我们也可以在struct中定义函数,在C++中,这是允许的但是不提倡使用,因为有一个比它更好使用的复杂数据类型,叫做类(这在稍后做出介绍)。

   使用struct的时候有一个问题:在进行一个比较大的项目工程的时候,我们的数据结构的定义和使用可能在不同的文件中,当我们修改了数据结构中的某个成员,那么,使用该数据结构的函数必须修改,而我们并不知道拿下函数使用该种数据结构,这时候我们怎么做?答案很简单,在函数定义的时候,让该函数属于该数据结构,在再次查找修改函数的时候,只要属于该结构的函数就进行修改就好了,代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
声明数据结构:
struct  Time{
     int  hour;
     int  minute;
     int  second;
     void  set_time( int  h,  int  m,  int  s); 
     void  tick();
     void  show();
     void  run();
};
定义函数:
void  Time::set_time( int  h,  int  m,  int  s){}
void  Time::tick(){}
void  Time::show(){}
void  Time::run(){}

补充:成员运算符:表示某个变量的成员,‘.’;表示某个类型的成员,“::”;

类的引出

   这样定义就万事大吉了吗?我们如果在其他函数中试图访问该结构中的成员变量(如:hourminutesecond)是成功的,这样我们就有可能无意中修改了数据结构中的某个成员变量的值,当其他函数在使用成员变量的时候,就会使用该可能非法的数据,这样我们就会想到只要让这些成员变量变成私有的就好了,这样除了结构中定义的函数外,其他方式都不可以访问到该成员,这就出现了我们C++常使用的一种数据结构——类。我们进行如下修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
声明数据结构:
class  Time{
     int  hour;
     int  minute;
     int  second;
     void  set_time( int  h,  int  m,  int  s); 
     void  tick();
     void  show();
     void  run();
};
定义函数:
void  Time::set_time( int  h,  int  m,  int  s){}
void  Time::tick(){}
void  Time::show(){}
void  Time::run(){}

如果我们就止步于上面的数据结构,我们定义一个上述类的对象,当我们通过对象调用函数的时候,会发现编译不会通过,提示我们“你访问的对象是私有的”。这里就要说明classstruct最大的区别:struct中的所有成员默认是公开的(public),即任意一个函数都可以进行访问;class中的所有成员默认是私有的(private),即除了class中的成员函数之外,其他方式不可以访问。

我们使用class而不是用struct的原因是因为,我们想让成员变量变成私有的,实现基本数据封装。但是对于成员函数的调用接口我们不必要私有,因为我们创建的对象,要通过成员函数完成项目任务,所以我们应让成员函数的接口公开(public),这就是我们常说的封装。接着进行如下更改,让成员函数变量公有的(public)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
声明数据结构:
class  Time{
private
     int  hour;
     int  minute;
     int  second;
public
     void  set_time( int  h,  int  m,  int  s); 
     void  tick();
     void  show();
     void  run();
};
定义函数:
void  Time::set_time( int  h,  int  m,  int  s){}
void  Time::tick(){}
void  Time::show(){}
void  Time::run(){}

在这里我们要说说class中成员变量的访问权限:

1private:私有的。这是class中成员变量默认的访问权限,这种权限的成员变量,只有该类中成员函数可以访问,子类中的成员函数不可以访问,其他方式也不可以访问。(子类是继承中的概念,在讲继承的时候再谈这个话题,先了解就好)。

2protected:保护的。该class中的成员函数可以访问,子类中的成员函数也可以访问,但是其他方式不可以访问。

3public:公开的。该class中的成员函数可以访问,子类中的成员函数也可以访问,其他方式亦可以访问。

 构造函数和析构函数

对于class中的成员函数,我们可以自己写一个函数进行初始化,比如set函数,将每个成员变量进行初始化赋值。但是每次创建一个新类都要调用该种函数进行成员的初始化,这大大加大了我们创建使用类的代价,为了让我们每次创建一个对象的时候,都可以自动调用某个函数进行成员变量的初始化,我们可以使用类中重要的成员函数——构造函数(构造函数无返回值,并且函数名与类名一致),它可以在创建对象的时候自动调用,根据创建对象时传入的初始化参数进行成员变量的初始化。

构造函数的格式:Class_name(parameters){}

构造函数的初始化有两种方式:

1)通过在构造函数内部进行赋值进行初始化,常量不能被赋值,只能使用初始化列表。

2)通过初始化列表进行初始化,如果成员变量是数组或结构不能使用初始化列表进行初始化。

构造函数的重载:有时候我们需要定义多个构造函数,因为我们可能基于不同的需求对成员变量的初始化操作不同,这就是构造函数的重载(函数重载:函数名相同,但是函数参数不同。系统可以根据传入参数的不同来调用不同的函数)。

析构函数:存在构造函数也就会存在析构函数,析构函数就是在该对象即将被释放的时候做收尾动作,析构函数一定没有参数列表,所以析构函数不可以重载。

  析构函数规则:~Class_name(){} 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class  A{
      int  n;
      double  d;
  public  :  A():n(0),d(0.0){    // constructor_init1
          }
          A( int  n){         // constructor_init2
              this ->n = n; 
              d = 0.0;           
          }
          void  show(){
              cout <<  "n = "  << n <<  ", d = "  << d << endl;
          }
          ~A(){
             cout << “~A()” << endl;
          }
};
int  main( int  ac,  char  *av[])
{
     A a1;             // use constructor_init1
a1.show();
     A a2(100);         // use constructor_init2
     (* this ).show();
     return  0;
}

   this指针:this指针是系统自动定义的,用来保存结构变量的地址。当我们创建一个对象的时候,系统就会自动将该对象对应的类的成员保存在this中,我们可以通过this->mem_valthis->mem_func,来访问该成员。在一个成员函数中,可以不用写this,表示默认使用该成员函数所在类的成员变量。

   构造函数总结:

   (1)构造函数不同写返回值,其函数名与类名一致。

 (2)构造函数在每个对象创建的时候都不被自动调用一次。

 构造函数的调用顺序

    ·全局对象的构造函数在main之前调用。

    ·静态局部对象的构造函数在整个程序的执行过程中只调用一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class  A{
    int  n;
public :
    A( int  n) : n(n){
          cout <<  "A("  << n <<  ')'  <<  endl;
     }   
     ~A(){
         cout <<  "~A("  << n <<  ')'  << endl;
     }   
};
void  func(){
     A a2(2);
     static  A a3(3);
}
int  main( int  ac,  char  *av[])
{
     A a4(4);
     cout <<  "first call func : \n" ;
     func();
     cout <<  "second call func : \n" ;
     func();
  
     return  0;
}
A a1(1); 
//==========================
// 1:全局对象
// 2:函数func中的自动对象
// 3:函数func中的静态全局对象
//4:函数main中的自动对象
//===============================
结果显示:
[root@anna-laptop construtor]# ./call_queue 
A(1)  
A(4)
first call func : 
A(2)
A(3)
~A(2)
second call func : 
A(2)
~A(2)
~A(4)
~A(3)
~A(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值