cpp类(一):基础知识

2019-05-23  本文已影响0人  浩波千里

这些对象并不”抽象“,它们像int和float一样实际
——Doug Mcllroy

C++类概念的目标是提供一种建立新类型的工具,使得新类型的使用像内部类型一样方便。此外,派生类和模板提供了组织的方法,使得类与类之间的关联更为密切
一个类型是某概念的具体体现,例如C++内部类型float及其四则运算是对数学中实数概念的一个具体近似一个类就是一个用户定义类型。这一节我们学习定义类,创建类的对象,操作类的对象基本功能

定义类

类的定义十分简单,就像下面这样

class <classname>{
//...
};

{}里包括起来的,有这个类的属性以及成员函数,我们还通过关键字private, public, protected控制访问权限。
以一个具体的Date为例,它是这样定义的

class Date
{
private:
    int day, month, year;     //Date对象具有day, month, year这些属性,它们是int类型的
    char * description="  ";    //Date对象还有description属性,是一个字符串
public:
    void init(int day, int month, int year, char *description)    //这是一个成员函数
    {
        this->day = day;    
        //this 是一个特殊的指针,这一点在下面说明,
        //这条语句是将形参day赋值给Date对象中的day
        this->month = month;
        this->year = year;
        this->description = description;
    }
    void print()    //这又是一个成员函数,定义起来和普通函数无异
    {
        cout<<setw(4)<<"Year"<<setw(8)<<"Month"<<setw(10)<<"Day"<<endl;
        cout<<setw(2)<<this->year<<setw(8)<<this->month<<setw(8)<<this->day;
        if (description) cout<<"\nThat day is:      "<<description;
    }

};

创建对象

我们可以通过

<classname> object_name;

这样的语法实例化一个类,即是创建一个这个类的对象,一个特定类的对象意味着我们可以该对象有该类的属性以及成员函数。
通过点号(.)标记法,我们可以访问该对象的属性值,也可以调用成员函数,过程就像下面这样


    Date my_date;
    my_date.init(8, 3, 2019, "Women's day");
    my_date.print();

在这里,调用print()函数会把对象的属性等显示出来,输出结果就是

Year   Month       Day
2019       3       8
That day is:      Women's day

创建类的一些细节

以上就是关于类的非常基础的内容,下面我们关注在创建一个类的过程中一些细节。

...
bool cmp_year(Date & d)
    {
        return (this->year > d.year);
    }

...

Date my_new_date = Date(2019, 3, 9);
Date yr_new_date(2018, 5, 1, "Labor's day");
if(my_new_date.cmp_year(yr_new_date)){
cout<<"My_New_Date is Bigger.";
}else{
cout<<"My_New_Date is Smaller";
}
...
void main(){
    Date my_date;    //这里是将Date类实例化,产生对象my_date
    my_date.day = 1;    //试图对my_date的day属性赋值,出现错误
    ...
}

这样做便是错误的,因为day是私有的,无法被外界访问.

...
public:
    Date(int year, int month, int day)
    {
        this->year = year;
        this->day = day;
        this->month = month;
    }
    Date(int year, int month, int day, char * description)
    {
        this->day = day;
        this->month = month;
        this->year = year;
        this->description = description;
    }
    Date()
    {
        this->day = 1;
        this->month = 1;
        this->year = 1;
        this->description = "Default Setting";
    }

上面的成员函数Date()就是构造函数,我们可以发现构造函数的特点:

  1. 不写返回值
  2. 必须与该类同名

此外,示例代码还告诉我们函数重载在这里同样有效,实际上重载的规则也是一致的
当有构造函数且要初始化对象时,可以像下面这样做


Date my_new_date = Date(2019, 3, 9);
//严格形式,这里的构造函数对应Date(int year, int month, int day)
Date yr_new_date(2019, 5, 1, "Labor's day");
//简写,对应Date(int year, int month, int day, char * description)
Date default_date;
//这里没有向构造函数传值,所以调用的是没有参数的函数Date()

对三个对象均调用print(),有如下结果:

Year   Month       Day
2019       3       9
That day is:
Year   Month       Day
2019       5       1
That day is:      Labor's day
Year   Month       Day
 1       1       1
That day is:      Default Setting

还可以对构造函数进一步细分,有两类特殊的构造函数值得注意:

  1. 默认构造函数
    它是在未提供显式初始值时用来创建对象的构造函数,像是这个语句Date my_date,实际上C++提供了默认构造函数,是隐式的,不做任何工作,对于Date而言,默认构造函数如同Stock::Stock() { }
    当且仅当没有定义任何构造函数时,编译器才会提供默认构造函数。
~<classname>(){...};

这里不再具体给出示例

class Test
{
static int temp;
public:
static int getData()
{
return temp;
}
};
int Test::temp=3;
int main()
{
cout <<Test::getData()<<endl;
return 0;
}

运行得到的结果是3,总结以下静态成员的特点:

  1. static修饰
  2. 静态成员必须在类外初始化,如例子中的temp
  3. 静态函数可以被类调用,写成Test::getData()这样的形式,普通的成员函数不可以被类直接调用;同样可以通过类来获取静态成员(形式如Test::temp)而不可通过某对象获取

再看一个更为实际的应用,我们想要确定Date类到底创建了多少对象,可以做如下修改:

private:
    ...
    static int obj_num;    //声明静态变量obj_num用于存储对象个数
public:
    static int get_counted(){
        return obj_num;
    }
    Date(int year, int month, int day)
    {
        ...
        obj_num++;    //每次析构函数执行一次便将obj_num递增一次

    }
...
int Date::obj_num = 0;   //静态变量一定要在外围声明!!!
int main()
{...

这是静态成员的一种常见用法


...
int get_day() const { return this->day;}

通过使用const标识,指明了这个函数不会修改Data的状态,像是下面这个函数就是有误的

int get_day() const { 
return this->day++;    //错误:在const函数内企图修改成员值
}
class TestCase1
{
private:
    int t;
public:
    TestCase1(int t=1)
    {
        this->t = t;
    }
    friend TestCase2 invite(TestCase1 obj);
};

class TestCase2
{
private:
    char s;
public:
    TestCase2(char s='a')
    {
        this->s = s;
    }
    get_ch()
    {
        return this->s;
    }
};

TestCase2 invite(TestCase1 obj)
{
    return obj.t<10? TestCase2():TestCase2('b');
}
int main()
{
    TestCase1 t1();
    TestCase1 t2(12);
    TestCase2 t3=invite(t1);
    TestCase2 t4=invite(t2);
    cout<<t3.get_ch();
    cout<<t4.get_ch();
}
···
###类作用域
上一篇 下一篇

猜你喜欢

热点阅读