【第三章】关于类和对象的进一步讨论

3.1构造函数

特点:
(1)构造函数的名字与它的类名必须相同。
(2)它没有类型,与不返回值
(3)它可以带参数,也可以不带参数。

#include <iostream>
using namespace std;
class Time{
    public:
        Time(){//构造函数
            hour = 0;
            minute = 0;
            sec = 0;
        }
        //此处也可以只写Time();
        
        void set_time();
        void show_time();

    private:
        int hour;
        int minute;
        int sec;
};
//在类外构造函数
 /*
 Time::Time(){
 	hour = 0;
   	minute = 0;
   	sec = 0;
}
*/
int main(){
    Time t1;
    t1.set_time();
    t1.show_time();
    Time t2;
    t2.show_time();
    return 0;
}
void Time::set_time(){
    cin >> hour;
    cin >> minute;
    cin >> sec;
}

void Time::show_time(){
    cout << hour << ":" << minute << ":" << sec << endl;
}

构造函数没有返回值,因此不需要在定义中声明类型。

构造函数可以带参数:
构造函数名(类型 形参1,类型 形参2);

定义对象格式:
类名 对象名(实参1,实参2);

#include <iostream>
using namespace std;
class Box{
    public:
        Box(int, int, int);
        int volume();

    private:
        int height;
        int width;
        int length;
};
Box::Box(int h, int w, int len) {// 长方体构造函数
    height = h;
    width = w;
    length = len;
}

int Box::volume() {//  计算长方体的体积
    return (height * width * length);
}
int main(){
    Box box1(12, 25, 30); // 定义对象box1
    cout << " box1体积=" << box1.volume() << endl;
    Box box2(15, 30, 21); // 定义对象box2
    cout << " box2体积= " << box2.volume() << endl;
    return 0;
}

也可以用形参初始化表的构造函数:

Box::Box(int h, int w, int len) : height(h), width(w), length(len) {}

构造函数也可以重载,在一个类中可以有多个重名的构造函数,但是参数个数、类型各不相同。

Box box1;
Box box2(1,1,1);

构造函数形参表可以带默认值,形参名也可以忽略

Box(int =10,int =10,int =10); 

3.2 析构函数

特殊的成员函数,作用与构造函数相反,收回对象占用的内存空间。
执行时机:
(1)函数结束时
(2)static局部对象、全局对象要等main结束或者exit命令
(3)new建立的动态对象,用delete时自动析构

#include <iostream>
#include <string>
using namespace std;
class Student{
    public:
        Student(int n, string nam, char s){
            num = n;
            name = nam;
            sex = s;
            cout << "Constructor called." << endl;
        }
        ~Student(){
            cout << "Destructor called." << endl;
        }
    //以~符号开始后面跟类名,没有数据类型、返回值、形参,但是可以执行其他操作
        void display(){
            cout << "num:" << num << endl;
            cout << "name:" << name << endl;
            cout << "sex:" << sex << endl
                << endl;
        }

    private:
        int num;
        string name;
        char sex;
};
int main(){
    Student stud1(10010, "Wang_li", 'f');
    stud1.display();
    Student stud2(10011, "Zhang_fun", 'm');
    stud2.display();
    return 0;
}

3.3调用析构函数和构造函数的顺序

先调用构造函数,最后调用析构函数。
先构造的后析构(栈,先进后出)
自定义局部自动对象,在函数调用结束时析构。
静态局部对象或全局变量,在主函数结束或调用exit函数时析构。
例如:

Void fn(){
    student st1;        //  定义局部自动对象
    static student st2; //   定义静态局部对象
    
}
//对象st1是每次调用函数fn时调用构造函数在函数fn结束时调用析构函数。
//对象st2是第一次调用函数fn时调用构造函数在函数fn结束时并不调用析构函数,在到主函数结束时才调用析构函数。

3.4对象数组

Student std[50];
//可以这样构造函数
Student::Student(int =1001,int =18,int =60);

在建立对象数组时,分别调用构造函数,对每个对象初始化。每个元素的实参用括号括起来,实参的位置与构造函数形参的位置一一对应,不会混淆。

student std[3] = {
    student(1001, 18, 87),
    student(1002, 19, 76),
    student(1003, 18, 80)}; //  构造函数带实参

举个栗子:

#include <iostream>
using namespace std;
class Box{
    public:
        Box(int h = 10, int w = 12, int len = 15) : height(h), width(w), length(len) {} // 带默认参数值和参数表
        int volume();

    private:
        int height;
        int width;
        int length;
};
int Box::volume(){
    return (height * width * length);
}
int main(){
    Box a[3] = {Box(10, 12, 15),
                Box(15, 18, 20),
                Box(16, 20, 26)};
    cout << "a[0]的体积是 " << a[0].volume() << endl;
    cout << "a[1]的体积是 " << a[1].volume() << endl;
    cout << "a[2]的体积是 " << a[2].volume() << endl;
    return 0;
}
// 每个数组元素是一个对象

3.5对象指针

指向对象的指针:

类名 *变量名表

Time *pt; // 定义pt是指向Time类对象的指针
Time t1;  //  定义Time类对象t1
pt = &t1; // 将对象t1的地址赋予pt
//访问方式:
(*pt).hour
pt->hour(*pt)
.show_time()
pt->show_time()

指向对象公有数据成员的指针:

定义:数据类型 *指针变量名
地址:&对象名.成员名

Time t1;
int *p1;       //  定义一个指向整型数据的指针变量
p1 = &t1.hour; // 假定hour是公有成员
cout << *p1 << endl;

指向对象成员函数的指针:

定义:数据类型(类名::*变量名)(形参表);
地址: &类名::成员函数名
赋初值:指针变量名 = &类名::成员函数名;
指针变量调用成员函数:(对象名.*指针变量名)([实参表]);

举个栗子:

#include <iostream>
using namespace std;
class Time{
    public:
        Time(int, int, int);
        int hour;
        int minute;
        int sec;
        void get_time();
};
Time::Time(int h, int m, int s){
    hour = h;
    minute = m;
    sec = s;
}
void Time::get_time(){
    cout << hour << ":" << minute << ":" << sec << endl;
}
int main(){
    Time t1(10, 13, 56);
    int *p1 = &t1.hour; //   定义指向成员的指针p1
    cout << *p1 << endl;
    t1.get_time();        //    调用成员函数
    Time *p2 = &t1;       //    定义指向对象t1的指针p2
    p2->get_time();       //    用对象指针调用成员函数
    void (Time::*p3)();   //   定义指向成员函数的指针
    p3 = &Time::get_time; //  给成员函数的指针赋值
    (t1.*p3)();           //  用指向成员函数的指针调用成员函数
    return 0;
}
运行结果:
10              // *p1的值
10:13:56    //  t1.get_time(); 的执行结果
10:13:56    //  p2->get_time(); 的执行结果
10:13:56    //  (t1.*p3)(); 的执行结果

this指针:
C++ 通过编译程序,在对象调用成员函数时,把对象的地址赋予this 指针,用this 指针指向对象,实现了用同一个成员函数访问不同对象的数据成员。


int Box ::volume(*this){
    return (this->height * this->width * this->length);
}

可省略this

3.6公用数据的保护

格式:
const 类名 对象名(实参表);
类名 const 对象名(实参表);

在这里插入图片描述
指向常对象的指针:
格式:类名 * const 指针变量名 = 对象地址

Time t1(10, 12, 15),t2;
Time *const p1 = &t1;

此后的程序中不能修改p1。

对象的常引用:
格式:const 类名 &形参对象名

#include <iostream>
using namespace std;
class Time{
    public:
        Time(int, int, int);
        //此处可改为
        //void fun(const int &t);
        //则不能改变实惨t1的值
        void fun(int &t)
        {
            hour = t;
            t = 18;
        }

        int hour;
        int minute;
        int sec;
};
Time::Time(int h, int m, int s){
    hour = h;
    minute = m;
    sec = s;
}
int main(int argc, char *argv[]){
    int x = 15;
    Time t1(10, 13, 56);
    t1.fun(x);
    cout << t1.hour << endl;
    cout << x << endl;
    return 0;
}

在这里插入图片描述

3.7 对象的动态建立和释放

格式: new 类名

Box *pt;
pt = new Box;
//如分配内存成功,就可以用指针变量pt访问动态对象的数据成员。
cout<< pt->height;
cout << pt->volume();

释放格式: delete 指针变量

3.8对象的赋值和复制

赋值格式: 对象1=对象2
注意:
(1)对象的赋值只对数据成员操作。
(2)数据成员中不能含有动态分配的数据成员。

复制格式:
类名 对象2(对象1);
类名 对象2=对象1,对象3=对象1,…;

Box ::Box(const Box &b){
    height = b.height;
    width = b.width;
    length = b.length;
}

3.9静态成员

静态数据成员格式:static 类型 数据成员名
几点说明:
(1)只能类外初始化。
(2)程序开始时分配内存空间,结束时释放
(3)作用域为类的作用域,访问格式为 类名::静态成员名

静态成员函数格式:static 类型 成员函数(形参表){…}
在这里插入图片描述
静态成员函数不带this指针,所以必须要用对象名.成员名访问

#include <iostream>
using namespace std;
class Point{
    private: // 私有数据成员
        int X, Y;
        static int countP;

    public: // 外部接口
        Point(int xx = 0, int yy = 0){
            X = xx;
            Y = yy;
            countP++;
        }
        Point(Point &p); // 拷贝构造函数
        int GetX() { return X; }
        int GetY() { return Y; }
        static void GetC(){
            cout << " Object id=" << countP << endl;
        }
};
Point::Point(Point &p){
    X = p.X;
    Y = p.Y;
    countP++;
}
int Point::countP = 0;
int main(){
    Point A(4, 5); //   声明对象A
    cout << "Point A," << A.GetX() << "," << A.GetY();
    A.GetC();   //   输出对象号,对象名引用
    Point B(A); //   声明对象B
    cout << "Point B," << B.GetX() << "," << B.GetY();
    Point::GetC(); //    输出对象号,类名引用
    return 0;
}

输出结果:
Point A,4,5 Object id=1
Point B,4,5 Object id=2

3.10友元

在A类外定义函数,如果是A的友元,则可以访问A中的所有成员(老板是下属的友元)
格式:
friend 类型 类1::成员函数x(类2 &对象);
friend 类型 函数y(类2 &对象);
x与y是友元函数

#include <iostream>
#include <math.h>
using namespace std;
class TPoint{
    private:
        double x, y;

    public:
        TPoint(double a, double b){
            x = a;
            y = b;
            cout <<"点:("<<x<<", "<<y<<") "<<endl;
        }
        friend double distance(TPoint & a, TPoint & b){ // 通过对象访问私有数据成员
            return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
        }
};
/*double distance(TPoint &a, TPoint &b)
	{   //通过对象访问私有数据成员
		return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
	}*/
int main(int argc, char* argv[]){
	TPoint myp1(2.1,1.3), myp2(5.4,6.5);
	cout<<"两点之间的距离为";
	cout<<distance(myp1,myp2)<<endl;
	return 0;
}

友元成员函数:
格式:friend 类型 类名::函数名(形参表)

friend void Time::display(const Date &);
/*友元是单向的,此例中声明Time的成员函数display是Date类的友元,允许它访问Date类的所有成员。但不等于说Date类的成员函数也是Time类的友元。*/

友元类:
在B类中声明A类为友元类的格式:
friend A;

3.11类模板

格式:template <class 类型参数名>
class 类模板名{…}

template <class numtype>
class Compare{
    private:
        numtype x, y;
    public:
        Compare(numtype a, numtype b) {//  构造函数
            x = a;
            y = b;
        }
        numtype max(){
            return (x > y) ? x : y;
        }
        numtype min(){
            return (x < y) ? x : y;
        }
};

在类模板外定义成员函数格式:
类型参数 类模板名<类型参数>::成员函数名(形参表) {…}

template <class numtype>
class Compare
{
    public:
        Compare(numtype a, numtype b){
            x = a;
            y = b;
        }
        numtype max();
        numtype min();

    private:
        numtype x, y;
};
numtype Compare<numtype>::max(){
    return (x > y) ? x : y;
}
numtype Compare<numtype>::min(){
    return (x < y) ? x : y;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

404Gloria

你的鼓励是我创作的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值