c++学习笔记

C++类和对象基础知识

2020-07-12  本文已影响0人  檀香静雪

类和对象

在c语言中,程序是由若干的函数以及变量组成的,它们之间并没有很严格的关系,这就导致了当程序规模逐渐变大之后,就不易于程序的扩充以及维护。另外,当我们想要复用之前程序中的一些代码片段时,函数中的变量使得我们很难将其从程序中抽离出来。总之,结构化程序设计使得我们的程序难以扩充、难以维护、难以重用。

c++在c语言的基础上增加了面向对象程序设计(Object-oriented programming,OOP)的机制,而面向对象的这种机制恰好解决了c语言结构化设计的这种缺陷。简单来说,在面向对象程序设计中,我们可以依照以下的设计方法:

  1. 我们将某类客观事物的共同特点(属性)归纳出来,形成一个数据结构,可以用多个变量描述事物的属性。
  2. 将这类事物所能进行的行为也归纳出来,形成函数,这些函数就用来操作数据结构。
  3. 然后通过某种方式将这些数据结构与函数捆绑封装起来,从而形成一个类。

需要注意的是,被封装的函数只能访问与它封装在一起的数据结构,反之,这些数据结构也只能被与它封装在一起的函数所操作。这样就使得某一类事物的数据结构只能由与之封装的函数进行操作,而其它函数是无法访问其数据结构的。

案例
假设我们现在要实现一个矩形类,该如何表示呢?

作为一个矩形,可以有哪些行为呢?

类的定义

我们将上面的矩形属性长(length)和宽(weight)以及与之对应的行为封装在一起,就能形成一个矩形类。

矩形属性成为“成员变量”,3个函数成为该类的“成员函数”,成员变量与成员函数统称为类的成员。

实际上,类看上去就像带函数的结构。

class Rectangle {
public:
    double length;//长
    double weight;//宽
    
    void init(double length_,double weight_) {//设置长和宽
        length = length_;//设置长
        weight = weight_;//设置宽
    }
    double Area(){//计算面积
        return length * weight;
    }
    double Perimeter() {//计算周长
        return 2 * (length + weight);
    }
};//分号不可省略

关键字 public 确定了类成员的访问属性。在类对象作用域内,公共成员在类的外部是可访问的。除了public,我们还可以指定成员为privateprotected,我们将在后续进行讲解。

这样我们就得到了一个矩形类。

定义 C++ 对象

普通定义

我们有了Rectangle类之后就要去使用它,声明类的对象,就像声明基本数据类型的变量一样,如下代码所示:

int main() {
    Rectangle r;//声明一个对象
    double length = 10.0;
    double weight = 10.0;
    r.init(length, weight);//初始化对象
    cout << "矩形面积为:" << r.Area() << endl;
    cout << "矩形周长为:" << r.Perimeter() << endl;
    return 0;
}

我们声明了一个对象r,类型为Rectangle我们通过.运算符可以访问类的成员,通过r.init(length, weight);来初始化对象,此时调用了类的成员函数void init(double length_,double weight_),设置了矩形的长和宽。

接下来,通过r.Area()以及r.Perimeter()计算矩形的面积以及周长,并通过cout输出,运行上面的代码,我们可以得到如下结果:

矩形面积为:100
矩形周长为:40

通过指针定义

除了上面所展示的普通定义之外,我们还可以通过指针来定义类的对象,其用法与基本数据类型的指针定义相同。

int main() {
    double length;//长
    double weight;//宽
    Rectangle *r;//声明一个对象指针
    r = new Rectangle;//为对象动态分配内存空间
    r->init(length, weight);//初始化对象
    cout << "矩形面积为:" << r->Area() << endl;
    cout << "矩形周长为:" << r->Perimeter() << endl;
    delete r;//释放动态分配的空间
    return 0;
}

对象指针的创建与基本数据类型的指针定义相同,通过Rectangle *r;创建一个对象指针,并通过new运算符为其动态分配内存空间,值得注意的是,在访问对象的成员时,需要使用->运算符进行访问,而不再是.运算符。

执行上面代码,我们可以获得与普通定义相同的结果:

矩形面积为:100
矩形周长为:40

最后,在使用完之后,我们需要使用delete运算符来释放动态分配的空间。

通过类可以定义变量,类定义出来的变量,也成为类的实例,就是我们所说的对象

访问数据成员

类的对象的公共数据成员(public)可以使用直接成员访问运算符.->来访问。

使用.访问

int main() {
    Rectangle r;//声明一个对象
    double length = 10.0;
    double weight = 10.0;
    r.init(length, weight);//初始化对象
    cout << "矩形长为:" << r.length << endl;
    cout << "矩形宽为:" << r.weight << endl;
    return 0;
}

执行上面的代码,得到如下结果:

矩形长为:10
矩形宽为:10

使用->访问

int main() {
    double length;//长
    double weight;//宽
    Rectangle *r;//声明一个对象指针
    r = new Rectangle;//为对象动态分配内存空间
    r->init(length, weight);//初始化对象
    cout << "矩形长为:" << r->length << endl;
    cout << "矩形宽为:" << r->weight << endl;
    delete r;//释放动态分配的空间
    return 0;
}

执行代码,得到下面结果:

矩形长为:10
矩形宽为:10

与使用.运算符的结果一致。

对象的内存分配

一般的,我们认为对象所占用的内存大小为,等于所有成员变量的大小之和

对于上面的Rectangle类,sizeof(Rectangle)=16

int main() {
    double length;//长
    double weight;//宽
    Rectangle r;//声明一个对象
    cout << "sizeof(Rectangle)=" << sizeof(Rectangle) << endl;
    return 0;
}

运行上面代码,得到如下结果:

sizeof(Rectangle)=16

注意

类的成员函数和类的定义分开写

当我们的类拥有很多的成员变量以及成员函数的时候,如果将所有的成员函数的实现都写在类的定义当中的话,就会显得十分的臃肿,不利于代码的阅读。此时,我们可以将类的定义以及实现分类来写,类的定义当中仅写成员函数的定义,而成员函数的实现则写到类的外面。

class Rectangle{
public:
    double length;//长
    double weight;//宽
    void init(double length_, double weight_);//设置长和宽
    double Area();//计算面积
    double Perimeter(); //计算周长
};//分号不可省略

我们改写上面所示的代码,在类的实现当中仅写成员函数的定义。将成员函数写在类外,如下代码所示:

void Rectangle::init(double length_, double weight_) {
    length = length_;
    weight = weight_;
}
double Rectangle::Area() {
    return length * weight;
}
double Rectangle::Perimeter() {
    return 2 * (length * weight);
}

其基本格式为:

返回值类型 类名::函数名(参数表){
    函数体
}

通过类名::说明后面的函数为类的成员函数,而非普通函数。

类成员的可访问范围

在类的定义中,用以下的关键字来说明类成员的访问范围:

class Student {
    char name[10];//默认为private
public:
    char sex;
    void printInfo();
private:
    int age;
protected:
    time_t birthday;
};

例如在上面的学生类中,name属性没有指定访问范围,值默认缺省为private

对于上面的类,假设我们有如下外部调用:

int main() {
    Student stu;
    stu.printInfo();//OK
    stu.sex;//OK
    stu.name;//错误,不能访问私有成员
    stu.birthday;//错误,不能访问保护成员
}

我们仅能访问类的公有成员(public),不能访问其它属性的成员。

对于如下的内部调用:

void Student::printInfo() {
    cout << age << endl;//OK
    cout << birthday << endl;//OK
}

在类的成员函数内部,我们可以访问所有的成员。

注意

设置私有成员的的机制叫“隐藏”,隐藏的目的时强制成员变量的访问一定要通过成员函数进行,使得成员变量不能被外部所访问到,确保了成员变量的安全,同时也易于以后的维护。

成员函数的重载与缺省

类的成员函数也可以进行重载以及缺省参数值,其用法与普通函数的重载与参数缺省相同。

上一篇 下一篇

猜你喜欢

热点阅读