类与对象<五>

转眼北京就已经进入了寒冷的冬季了,如今也是晚上最适合睡觉的季节,每天早上都有种不想上班的冲动,只是没有暖气的日子也挺煎熬的,像南方老家冬天的那种感觉,上周末第一次练车,感觉还是挺刺激的,不过有点手忙脚乱,下周还得继续,这个月的目标是将证拿到手,得继续油啦~~~好了,随笔了一下,下面开始学习。

 

  • 在关键字public后面声明,它们是类与外部的接口,任何外部函数都可以访问公有类型数据和函数。
  • 在关键字private后面声明,只允许本类中的函数访问,而类外部的任何函数都不能访问。
  • 在关键字protected后面声明,与private类似,其差别表现在继承与派生时对派生类的影响不同。

对于熟悉Java的来说,对于类是太熟悉不过了,不过C++还是有它自身的特点,所以还是按部就班的学习,下面来新建一个类来体验下:

      

上面是自动生成的类相关的代码,对于初学者就手工去敲,其中对于头文件中有一句代码:

新建一个主函数来调用下,切到解决方案视图:

编译运行:

这时秒钟走了一秒,可以这样模拟:

因为second这个成员变量的访问修饰符是public的,所以类可以直接访问,而一般成员变量会声明成私的的,这时就需要暴露一个public的方法来对其进行更新,修改程序如下:

这样输出的结果还是一样,另外要去在外去单独去访问私有的成员变量,则需要生成成员变量的set和get方法,学过java的都很容易理解,具体代码如下:

Clock.h:

//#pragma once   它是防止头文件重复包含的,跟之前我们编写的等价
#ifndef _CLOCK_H_
#define _CLOCK_H_

class Clock {
public:
    void display();
    void init(int hour, int minute, int second);
    void update();
    
    int getHour();
    int getMinute();
    int getSecond();

    void setHour(int hour);
    void setMinute(int minute);
    void setSecond(int second);
private:
    int hour;
    int minute;
    int second;
};

#endif    //_CLOCK_H_

Clock.cpp:

#include "Clock.h"
#include <iostream>
using namespace std;

void Clock::display() {
    cout<<hour<<":"<<minute<<":"<<second<<endl;
}

void Clock::init(int hour, int minute, int second) {
    this->hour = hour;
    this->minute = minute;
    this->second = second;
}

void Clock::update() {
    this->second++;
    if(this->second == 60) {
        this->minute++;
        this->second = 0;
    }
    if(this->minute == 60) {
        this->hour++;
        this->minute = 0;
        this->second = 0;
    }
}

int Clock::getHour() {
    return this->hour;
}

int Clock::getMinute() {
    return this->minute;
}

int Clock::getSecond() {
    return this->second;
}

void Clock::setHour(int hour) {
    this->hour = hour;
}

void Clock::setMinute(int minute) {
    this->minute = minute;
}

void Clock::setSecond(int second) {
    this->second = second;
}

 关于它的概念在之前已经学习过,具体可以参考博文:http://www.cnblogs.com/webor2006/p/4896191.html

 而类中的成员函数也可以做成内联的,下面则通过代码来认识一下:

定义内联成员函数有两种方式:

方式一:

方式二:

 

 关于函数的重载这里就不多介绍,之前已经学过了,必须是在相同的作用域的前提下来说,而对于类的成员函数中也同样存在重载的情况,具体如下:

Test.cpp:

#include "Test.h"
#include <iostream>
using namespace std;

//inline int Test::add(int a, int b) {
//    return a + b;
//}

void Test::init() {
    this->x = 0;
    this->y = 0;
    this->z = 0;
}

void Test::init(int x) {
    this->x = x;
    this->y = 0;
    this->z = 0;
}

void Test::init(int x, int y) {
    this->x = x;
    this->y = y;
    this->z = 0;
}

void Test::init(int x, int y, int z) {
    this->x = x;
    this->y = y;
    this->z = z;
}

void Test::display() {
    cout<<"x="<<this->x<<" y="<<this->y<<" z="<<this->z<<endl;
}

编译运行:

实际上可以用缺省参数简化重载的代码,具体如下:

而调用的代码不用变,且结果也是一样的。另外需要注意一下可能会产生函数调用的恶意性,如下:

这时编译:

但是:

具体来看下代码:

编译运行:

实际上可以像c语言那样对struct结构体进行初始化,如下:

接着来看一下类,来跟结构体进行对比:

02.cpp:

#include <iostream>
using namespace std;

struct Test2 {
    int x;
    int y;
    int z;

    void init(int x, int y, int z) {
        this->x = x;
        this->y = y;
        this->z = z;
    }

    void display() {
        cout<<"x="<<this->x<<" y="<<this->y<<" z="<<this->y<<endl;
    }
};

class Test3 {
    int x;
    int y;
    int z;

    void init(int x, int y, int z) {
        this->x = x;
        this->y = y;
        this->z = z;
    }

    void display() {
        cout<<"x="<<this->x<<" y="<<this->y<<" z="<<this->y<<endl;
    }
};

int main(void) {

    /*Test2 test2;
    test2.init(10, 20, 30);
    test2.display();

    Test2 test2 = {10, 20, 30};
    test2.display();*/

    Test3 test3;
    test3.init(10, 20, 30);
    test3.display();

    return 0;
}

编译运行:

那类能不能像结构体那样进行参数初始化呢?

编译运行:

那如果声明成公有的,那这种初始化方式能支持么?

class Test3 {
public:
    int x;
    int y;
    int z;

    void init(int x, int y, int z) {
        this->x = x;
        this->y = y;
        this->z = z;
    }

    void display() {
        cout<<"x="<<this->x<<" y="<<this->y<<" z="<<this->y<<endl;
    }
};

int main(void) {

    /*Test2 test2;
    test2.init(10, 20, 30);
    test2.display();

    Test2 test2 = {10, 20, 30};
    test2.display();*/

    /*Test3 test3;
    test3.init(10, 20, 30);
    test3.display();    ERROR,成员是私有的,无法访问*/

    Test3 test3 = {10, 20, 30};
    test3.display();

    return 0;
}

这时编译运行:

可以看出类中的成员变量也可以像结构体那样进行初始化。

实际上对于这个关键字已经在上面用过了,java里面也有这个关键字,还是先看下介绍:

  • 成员函数有一个隐含的附加形参,即指向该对象的指针,这个隐含的形参叫做this指针。
    要说明白this指针,需要先从类的内存模型中来进行理解,一个类中由成员变量和成员函数构成,这里拿Test3这个类来进行说明:

    所以this指针就代表对象本身。
  • 使用this指针保证了每个对象可以拥有不同的数据成员,但处理这些成员的代码可以被所有对象共享。

每个类都定义了自己的作用域称为类作用域,如下面代码:

而类作用域中说明的标识符只在类中可见,也就是在类的外面则无法使用:

但是:

由作用域则引出五种作用域类别:

1、块作用域:在花括号以内的作用域

输出结果:

2、文件作用域

这个在上面有说到。

3、函数原型作用域

4、函数作用域:仅仅只是针对goto语句来说的,但goto语句不会用到,做个了解。

5、类作用域

  • C++中类必须先定义,才能够实例化。
  • 两个类需要相互引用形成一个“环形”引用时,无法先定义使用。这时候需要用到前向声明。
  • 前向声明的类不能实例化。

新建两个类:

这里面的代码都是默认的:

A.h:

#ifndef _A_H
#define _A_H

class A
{
public:
    A(void);
    ~A(void);
};


#endif

A.cpp:

#include "A.h"

A::A(void)
{
}

A::~A(void)
{
}

B.h:

#ifndef _B_H
#define _B_H

class B
{
public:
    B(void);
    ~B(void);
};

#endif

B.cpp:

#include "B.h"

B::B(void)
{
}

B::~B(void)
{
}

这时A类中包含B类,代码可以这样写:

上面的写法毋庸置疑,当然是合法的。

这时,B类中也包含了A类,代码可以这样写:

这就造成A类和B类相互包含,这在语法上是不允许的,编译如下:

这时就需要用上前向声明了,在B类中进行前向声明:

编译运行:

这个错是啥意思呢?也就是上面说的第三条:前向声明的类不能实例化。也就是只支持指针或引用,修改代码如下:

编译运行:

但是对于B.cpp实现文件而言,在要使用A类时还是需要包含A.h头文件的:

或者可以用在引用中,如下:

所以需要记住:当两个类相互包含时,需要用到前向声明。

  •  外围类需要使用嵌套类对象作为底层实现,并且该嵌套类只用于外围类的实现,且同时可以对用户隐藏该底层实现,具体代码如下:

  

  编译运行:

  

  •  从作用域的角度看,嵌套类被隐藏在外围类之中,该类名只能在外围类中使用。如果在外围类的作用域使用该类名时,需要加名字限定。

    编译运行:

    因为Inner对于外围类中是不可见的,需要加名字限定,如下:

    其运行结果是一样的。
  • 嵌套类中的成员函数可以在它的类体外定义。
    这个在上面已经看到了。
  • 嵌套类的成员函数对外围类的成员没有访问权,反之亦然。
    也就是不能访问私有成员,修改代码如下:

    编译运行:

    所以就是这个道理。
  • 嵌套类仅仅只是语法上的嵌入。

    编译运行:

    但是如果给内部类加上public关键字:

    编译运行:

    以上可以发现,并非嵌套类Inner只能被Outer使用,前提是被public修饰,实际上只是语法上的嵌入,在外界也可以用来使用,当然如果用private修饰Inner,则仅仅只有在Outer内部才能进行使用。

  • 类也可以定义在函数体内,这样的类被称为局部类(local class)。局部类只在定义它的局部域内可见。
  • 局部类的成员函数必须被定义在类体中。
  • 局部类中不能有静态成员。

    编译运行:

    那如果在函数外使用呢?当然会报错:



    这是由于静态数据成员需要在文件作用域外部才能够进行初始化,关于这点在之后会进一步学习。

posted on 2015-10-26 22:12  cexo  阅读(203)  评论(0)    收藏  举报

导航