实验1 类与对象

 

2 实验任务二

验证性实验。使用C++语言特性中支持面向对象的语法,实现一个Point类来描述点的基础属性和操作。
在C++编码环境中,输入以下代码,结合代码注释和运行结果,熟悉和掌握C++中类的定义、对象的创建
和使用。

#include<iostream>

using std::cout;
using std::endl;

class Point {
public:
    Point(int x0 = 0, int y0 = 0);
    Point(const Point &p);
    ~Point() = default;
    
    int get_x() const { return x; }
    int get_y() const { return y; }
    void show() const;
    
private:
    int x, y;
};

Point::Point(int x0, int y0): x{x0}, y{y0} {
    cout << "constructor called" << endl;
}

Point::Point(const Point &p): x{p.x}, y{p.y}{
    cout << "copy constructor called" << endl;
}

void Point::show() const {
    cout << "(" << x << ". "
                << y << ")" << endl;
}

int main() {
    Point p1(2, 3);
    p1.show();
    
    Point p2 = p1;
    p2.show();
    
    Point p3{p2};
    p3.show();
    cout << p3.get_x() << endl;    
}

 

 

 

3 实验任务三

验证性实验。使用C++语言特性中支持面向对象的语法,实现一个简单时钟类Clock。通过它实现对时钟
的设置、显示等基础操作。

#include <iostream>
#include <iomanip>

using std::cout;
using std::endl;

class Clock {
public:
    Clock(int h = 0, int m = 0, int s = 0);
    Clock(const Clock& t);
    ~Clock() = default;
    
    void set_time(int h, int m = 0, int s = 0);
    void show_time() const;
    
private:
    int hour, minute, second;
    
};

Clock::Clock(int h, int m, int s): hour{h}, minute{m}, second{s} {
    cout << "constructor called" << endl;
}

Clock::Clock(const Clock& t): hour{t.hour}, minute{t.minute},
second{t.second} {
    cout << "copy constructor called" << endl;
}

void Clock::set_time(int h, int m, int s) {
    hour = h;
    minute = m;
    second = s;
}

void Clock::show_time() const {
    using std::setw;
    using std::setfill;
    
    cout << setfill('0') << setw(2) << hour << ":"
         << setw(2) << minute << ":"
         << setw(2) << second << endl;
}

//普通函数定义
Clock reset() {
    return Clock(0, 0 ,0);
} 

int main()
{
    Clock c1{12, 0, 5};
    c1.show_time();
    
    c1 = reset();
    c1.show_time();
    
    Clock c2{c1};
    c2.set_time(6);
    c2.show_time();
    
    return 0;
} 

 

 

 

4 实验任务四

验证性实验。使用C++语言特性中支持面向对象的语法,实现一个抽象类X。它是对类和对象的基础操作
的一个抽象概括,覆盖了类的定义、实现、测试,包括各类构造函数、析构函数及其调用时机的观察。

 1 #include <iostream>
 2 
 3 class X{
 4 public:
 5     X();
 6     ~X();
 7     X(int m);
 8     X(const X& obj);
 9     X(X&& obj) noexcept;
10     void show() const;
11     
12 private:
13     int data;
14 };
15 
16 X::X(): data{42} {
17     std::cout << "default constructor called.\n";
18 }
19 
20 X::~X() {
21     std::cout << "destructor called.\n";
22 }
23 
24 X::X(int m) : data{m} {
25     std::cout << "constructor called.\n";
26 }
27 
28 X::X(const X& obj): data{obj.data} {
29     std::cout << "copy constructor called.\n";
30 }
31 
32 X::X(X&& obj) noexcept: data{obj.data} {
33     std::cout << "move constructor called.\n";
34 }
35 
36 void X::show() const {
37     std::cout << data << std::endl;
38 }
39 
40 int main() {
41     X x1;
42     x1.show();
43     
44     X x2{2022};
45     x2.show();
46     
47     X x3{x1};
48     x3.show();
49     
50     X x4{ std::move(x2) };
51     x4.show();
52 }

 

 

分析:

1.第41行语句调用了默认无参构造器,用默认值42初始化成员数据,

  第44行语句调用了有一个形参的有参构造器,

  第47行语句调用了复制构造函数,用已创建的对象x1来初始化新的对象x3,

  第50行语句调用了移动构造函数,将左值x2通过move方法移动为右值,作为实参。

 

2.析构函数在对象的生命周期即将结束时被自动调用,用以进行一些对象被删除前的清理工作。

通过test可以发现,析构函数的调用顺序与创建对象的顺序相反,即对象x4, x3, x2 , x1的析构函数依次执行。

 

 

5 实验任务五

#include <iostream>
#include <iomanip>

class Rectangle {
public:
    Rectangle();
    Rectangle(double l, double w);
    Rectangle(const Rectangle& obj);
    ~Rectangle() = default;
    
    double len() const {
        return length;
    }
    
    double wide() const {
        return width;
    }
    
    double area() const {
        return width * length;
    }
    
    double circumference() const {
        return 2 * (width + length);
    }
    
    void resize(int times);
    void resize(int timesOfL, int timesOfW);
    
private:
    double length, width;
};

Rectangle::Rectangle(): length(2.0), width(1.0) {}

Rectangle::Rectangle(double l, double w): length{l}, width{w} {}

Rectangle::Rectangle(const Rectangle& obj): length(obj.length), width(obj.width) {}

void Rectangle::resize(int times) {
    length *= times;
    width *= times;
}

void Rectangle::resize(int timesOfL, int timesOfW) {
    length *= timesOfL;
    width *= timesOfW;
}
void output(const Rectangle& rect) {
    using namespace std;
    
    cout << "矩形信息: \n"; 
    cout << "长:\t" << fixed << setprecision(2) << rect.len() << endl;
    cout << "宽:\t" << fixed << setprecision(2) << rect.wide() << endl;
    cout << "面积:\t" << fixed << setprecision(2) << rect.area() << endl;
    cout << "周长:\t" << fixed << setprecision(2) << rect.circumference() << endl;
    cout << endl;
} 

int main() {
    Rectangle rect1;
    output(rect1);
    
    Rectangle rect2(10, 5);
    output(rect2);
    
    Rectangle rect3(rect1);
    rect3.resize(2);
    output(rect3);
    
    rect3.resize(5, 2);
    output(rect3);
}

分析:

 

 

1.在output函数中,形参为const修饰的Rectangle对象的引用类型,而在函数体中调用到了该对象的成员函数,这就要求这些成员函数也是const的,以防止出现任何修改数据的情况。

2. fixed 和 setprecision(int n) 控制符常连用,使输出保留某浮点数小数点后指定位数。

 

实验总结

1. 类的抽象和封装使得某类事物的数据和对数据的操作方法逻辑上关联了起来,形成了一个有机的整体,数据和方法不再是互相孤立的存在。这样实现了程序世界对现实世界中事物更为高级的抽象,并且增加了程序的健壮性,更有利于进行对问题域全面的描述,增强了分析、处理效率。

 

2. 类的成员数据(变量)与成员函数(方法)的存在,在某种程度上,使得类类型能够像基本数据类型一样,进行各种对数据的处理操作,将所有类型进行了一定的统一。 由于基本类型的有限,自定义的数据类型可以用来描绘现实大千世界中形形色色的万物,这也是面向对象编程的一大魅力所在。

 

3. 封装,即将数据与方法结合在一起,隐藏内部的实现细节,这就要求数据一般是私有的,对类外是不公开的。

因此,类需要对外部暴露公共的接口(成员函数),来实现对数据的操作,如set,get方法。

这样有利于数据的安全,程序的复用性与可维护性。还有很关键的一点是,大大降低了一般开发人员的开发成本。

 

4. 关于构造函数:
    构造函数使得类类型的对象可以像基本类型一样进行各式的初始化操作,由编译器自动调用。这里的各式,正是由不同的构造函数来实现的。构造函数的重载,默认的构造函数,带默认形参值的构造函数,各式的变化,使得类对象的初始化可以真正做到灵活多变,从事物的基本特性出发,满足问题域中的各种复杂情况。

    关于析构函数:

    析构函数可以进行对象消亡前的一些清理工作,可见对象同万事万物一样,存在着一定的生命周期。对象的创建与清除,体现着内存分配的合理性。

     tips:

由于析构函数与构造函数是自动被调用的,所以可以根据需求,将一些语句写在其中,这样就避免了人为的主动调用。

默认构造函数一般需要显示地再定义一下,主要是因为合成的默认构造函数会被其他有参构造函数覆盖。

析构函数由于不含参数,因此无法进行重载。

 

 

         继续努力,长足进步!!

 

posted @ 2022-10-05 00:59  尤夏  阅读(12)  评论(0编辑  收藏  举报