c++类和对象

目录

类和对象

类的定义格式如下

成员访问权限

public(公有类型)

private(私有类型)

protected(保护类型)

成员函数实现方式

成员函数重载

对象的创建和使用

对象访问其成员

对象的指针访问其成员

对象的引用访问其成员

构造函数

构造函数

默认构造函数

自定义默认构造函数

1.定义无参的构造函数

参数有默认值的构造函数

析构函数

构造和析构的调用顺序

对象数组

对象指针

this指针


类和对象

类是一种自定义数据类型,是面向对象程序设计的核心,是对某一类对象的抽象。对象是类的实例。从广义上讲,类和对象就是数据类型与变量的关系,类相当于一种数据类型,而对象就是用数据类型定义的变量。

类的定义格式如下

class 类名 
{
private:
	成员属性或成员函数
protected:
	成员属性或成员函数
public:
	成员属性或成员函数
};

说明:
(1)class是声明类的关键字,class后跟类名。类名一般首字母大写。
(2)类包括成员属性和成员函数。成员属性代表对象的属性;成员函数实现对象的行为。
(3)private、protected和public关键字称为访问权限符,它规定了类中成员的访问属性。这3个关键字可以按任意顺序出现。默认时为私有的(private)。

例:声明一个学生类。
分析:每个学生都有学号、姓名和性别;对于学生的基本操作有输入信息、输出信息等。因此,对应的学生类定义如下:

class Student //声明类
{
private: //访问权限:私有成员
    string m_id;   //属性,数据成员,表示学号
    string m_name; //属性,数据成员,表示姓名
    string m_sex;  //属性,数据成员,表示性别
public:  //访问权限:公有成员
    Student();     //行为,成员函数的原型声明,表示构造函数
    void input();  //行为,成员函数的原型声明,表示输入学生信息
    void print();  //行为,成员函数的原型声明,表示输出学生信息
}; //类声明结束

成员访问权限

可以定义3种不同的访问权限符,分别为public(公有类型)、private(私有类型)和protected(保护类型)

public(公有类型)

public 声明成员为公有成员。完全公开。都可以访问。

class Human
{
public: //声明类的公有成员
    int high; //身高
    int weight;//体重
    void GetHigh()
    {
        cout<<"身高:"<<high<<endl;
    }
    void GetWeight()
    {
        cout<<"体重:"<<weight<<endl;
    }
};

int main()
{
    Human zhangsan;       //定义类的对象
    zhangsan.high=175;    //通过对象访问类的公有数据成员
    zhangsan.weight=70;   //通过对象访问类的公有数据成员
    zhangsan.GetHigh();   //通过对象访问类的公有成员函数
    zhangsan.GetWeight(); //通过对象访问类的公有成员函数

    return 0;
}

private(私有类型)

private声明成员为私有成员。该级别的成员只能被它所在类中的成员函数和该类的友元函数访问。

class Human
{
private: //声明类的私有数据成员
    int high; //身高
    int weight;//体重
public: //声明类的公有成员函数
    void SetHigh(int h)
    {
        high = h; //类的成员函数访问类的私有数据成员
    }
    void GetHigh()
    {
        cout << "身高:" << high << endl; //类的成员函数访问类的私有数据成员
    }
    void SetWeight(int w)
    {
        weight = w; //类的成员函数访问类的私有数据成员
    }
    void GetWeight()
    {
        cout << "体重:" << weight << endl; //类的成员函数访问类的私有数据成员
    }
};

int main()
{
    Human lisi; //定义类的对象
    //lisi.high=185; //错误,不能通过对象访问类的私有数据成员
    //lisi.weight=90; //错误,不能通过对象访问类的私有数据成员
    lisi.SetHigh(180); //通过对象访问类的公有成员函数给high赋值
    lisi.SetWeight(80); //通过对象访问类的公有成员函数给Weight赋值
    lisi.GetHigh(); //通过对象访问类的公有成员函数
    lisi.GetWeight(); //通过对象访问类的公有成员函数

    return 0;
}

从上例可知,private成员只能在类的成员函数中使用。在类外,不能通过对象访问

protected(保护类型)

protected声明成员为保护成员。具有这个访问控制级别的成员,外界是无法直接访问的。它只能被它所在类及从该类派生的子类的成员函数及友元函数访问。它和private的区别只在类继承时体现。
总结public、protected和private这3种访问限定符对应的类成员的可访问性如下表:

成员函数实现方式

类的成员函数也是函数的一种。它与一般函数的区别是:它属于一个特定的类,是类的一个成员。
在使用类的成员函数时,要注意它的访问权限(它能否被访问),以及它的作用域(类函数能在什么范围内被访问)。
类的成员函数的定义方式有两种
第一种是在类内直接进行定义。这种方式一般用在代码比较少的成员函数中,并自动成内联函数。
第二种是在类中进行函数说明,在类外进行函数定义。这种情况通常用在代码较多的类的成员函数上。在定义函数时,必须用作用域符“::”表明函数所属的类。
形式如下:

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

例如

#include <iostream>
using namespace std;
class Clock
{
private:
    int hour; //小时
    int minute;//分钟
    int second;//秒
public:
    void setTime(int h,int m,int s); //类中声明,类外定义
    
    void showTime() //类中定义函数
    {
        cout<<hour<< "时"<<minute<<"分"<<second<<"秒"<<endl;
    }
};

void Clock::setTime(int h,int m,int s) //定义成员函数
{
    hour=h;
    minute=m;
    second=s;
}


int main()
{
    Clock cc;
    cc.setTime(8,10,20);
    cc.showTime();
    return 0;
}

成员函数重载

成员函数重载是指在同一个类里,有两个以上的函数具有相同的函数名。每种实现对应着一个函数体,但是形参的个数或者类型不同。
例如:减法函数重载
创建一个类,在类中定义3个名为subtract的重载成员函数,分别实现两个整数相减、两个实数相减和两个复数相减的功能。

#include <iostream>
using namespace std;

struct Complex //复数类型
{
    double real;//实部
    double imag;//虚部
};

class Sub //减法重载类
{
public:
    int subtract(int x, int y);            //两个整数相减
    double subtract(double x, double y);   //两个double相减
    Complex subtract(const Complex &x, const Complex &y);//两个复数相减
};

int Sub::subtract(int x, int y)//两个整数相减
{
    return x - y;
}
double Sub::subtract(double x, double y)//两个double相减
{
    return x - y;
}
Complex Sub::subtract(const Complex& x, const Complex& y)//两个复数相减
{
    Complex c;
    c.real = x.real - y.real;  //实部相减
    c.imag = x.imag - y.imag;  //虚部相减
    return c;
}

int main()
{
    int m = 30;
    int n = 20;
    double x = 34.5;
    double y = 23.2;
    Complex a = {10,10};
    Complex b = { 5,5 };
    Sub s;
    cout << m << " - " << n << " = " << s.subtract(m, n) << endl;
    cout << x << " - " << y << " = " << s.subtract(x, y) << endl;
    Complex c = s.subtract(a, b);
    cout << "(" << a.real << "+" << a.imag
        << "i)" << " - " << "(" << b.real << "+" << b.imag << "i)"
        << " = " << "(" << c.real << "+" << c.imag << "i)" << endl;
    return 0;
}

对象的创建和使用

定义了类,就相当于定义了一个数据类型。类与int、char等数据类型的使用方法是一样的。可以定义变量,数组和指针等。使用类定义的变量通常称为该类的对象。
对象的定义格式如下:
类名 对象名;

对象访问其成员

对象通过"."访问它的成员变量和成员函数。

对象名.成员变量 //访问对象的成员变量.
对象名.成员函数 //访问对象的成员函数.
#include <iostream>
using namespace std;

class Date //日期类
{
private:
    int year;//年
    int month;//月
    int day;//日
public:
    void set(int y, int m, int d)//赋值操作,在类声明中定义
    {
        year = y;
        month = m;
        day = d;
    }
    bool isLeapYear() //判断闰年,在类声明中定义
    {
        return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
    }
	void show();//输出日期
};

void Date::show()//输出日期,在类声明外定义
{
    cout << year << "年" << month << "月" << day << "日" << endl;
}

int main()
{
    Date today;            //创建一个Date的对象,名字为today
    today.set(2023,4,21);  //today访问它的set函数
    today.show();          //today访问它的show函数
    if (today.isLeapYear())//today访问它的sisLeapYear函数
        cout << "今年是闰年" << endl;
    else
        cout << "今年不是闰年" << endl;		
    return 0;
}

对象的指针访问其成员

对象的指针通过"->"访问它的成员变量和成员函数。

对象的指针->成员变量
对象的指针->成员函数
#include <iostream>
using namespace std;

class Date //日期类
{
private:
    int year;//年
    int month;//月
    int day;//日
public:
    void set(int y, int m, int d)//赋值操作,在类声明中定义
    {
        year = y;
        month = m;
        day = d;
    }
    bool isLeapYear() //判断闰年,在类声明中定义
    {
        return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
    }
	void show();//输出日期
};

void Date::show()//输出日期,在类声明外定义
{
    cout << year << "年" << month << "月" << day << "日" << endl;
}

int main()
{
	Date today;
	today.set(2023,4,21);
	Date* pd = &today;
	pd->show(); //对象指针通过->访问它的成员

	return 0;
}

对象的引用访问其成员

对象定义一个引用变量,它们是共占同一段存储单元的,实际上它们是同一个对象,只是用不同的名字表示而已。因此完全可以通过引用变量来访问对象中的成员。
    对象定义引用的方式:

类型 &引用变量名=对象名;
#include<iostream>
using namespace std;

class Time //时间类
{
public :
    int hour;  //小时
    int minute;//分钟
    int second;//秒
    void showTime();//显示时间
};

void Time::showTime()
{
    cout<<hour<<"时"<<minute<<"分"<<second<<"秒"<<endl;
}

int main()
{
    Time t1 = {16,48,56}; //创建Time对象t1
    Time &t2=t1;   //t2是t1的引用
    t1.showTime(); //通过t1访问其成员函数
    t2.showTime(); //通过引用变量访问对象的成员函数
    return 0;
}

构造函数

构造函数

是一种特殊的成员函数,专门用于构造新对象,并把数据赋值给它的成员。
构造函数在类内的定义格式如下:

类名(参数列表)
{
    函数体;
}

构造函数可以在类内也可在类外定义。在类外定义构造函数的形式如下:

类名::类名(形参列表)
{
    函数体;
}

说明:
(1)构造函数的名称必须与类名相同。
(2)构造函数没有返回值类型,也不能指定为void。
(3)构造函数可以重载,即可以有多个构造函数。
(4)如果没有显式定义构造函数,系统会自动生成一个默认的构造函数。这个构造函数不含参数,也不对数据成员进行初始化,只负责为对象分配存储空间。
(5)如果显式地为类定义了构造函数,系统将不再为类提供默认构造函数。
(6)定义对象时,系统会自动调用构造函数。
(7)构造函数一般被定义为公有访问权限。

默认构造函数


不需要提供参数的构造函数,可以由系统提供(不写任何构造函数)或程序提供(定义无参构造函数,或所有参数都有默认值的构造函数)。
1.系统自动生成默认构造函数
如果你没有编写任何构造函数则系统会自动生成默认构造函数。它只负责为对象分配存储空间,而不对数据进行初始化。

注意:系统虽然可以生成默认构造函数,但它并不是给我们使用的,我们一定要定义自己的构造函数

自定义默认构造函数

1.定义无参的构造函数

#include<iostream>
using namespace std;

class Point //点类
{
private:
    int x; //x坐标
    int y;//y坐标
public:
    Point() //默认构造函数,也是无参构造函数
    {
        cout << "自定义默认构造函数" << endl;
        x = 0;  //自己定义的就可以对成员变量进行初始化
        y = 0;
    }
    void show()//输出函数
    {
        cout << "x=" << x << ",y=" << y << endl;
    }
};

int main()
{
    Point p2;
    p2.show();

    return 0;
}

参数有默认值的构造函数

#include<iostream>
using namespace std;

class Point //点类
{
private:
    int x; //x坐标
    int y;//y坐标
public:
    Point(int m = 10, int n = 10) //所有参数都有默认值的构造函数
    {
        cout << "自定义构造函数,所有参数都有默认值" << endl;
        x = m;
        y = n;
    }
    void show()//输出函数
    {
        cout << "x=" << x << ",y=" << y << endl;
    }
};

int main()
{
    Point p1;//使用默认的值
    p1.show();

    Point p2 = { 100,200 };//传入实参
    p2.show();

    return 0;
}

说明:
(1)默认参数只能最上面给,不能多处给定(避免不一致)
(2)带默认值的参数必须在最右面。
(3)有默认参数时,注意避免重定义。
上面三点和普通带默认值的函数一样,在这仅仅是提醒.

析构函数

当对象的生存期结束时,系统就会自动执行析构函数清除其数据成员所分配的内存空间。

析构函数的定义格式为:

~类名();//没有返回值,没有参数

说明:
(1)析构函数名是由“~”加类名组成的。
(2)析构函数没有参数、没有返回值,不能重载。
(3)一个类有且仅有一个析构函数,必须为public。
(4)在对象的生存期结束时,由系统自动调用析构函数。
(5)如果没有定义析构函数,系统会自动生成一个默认的析构函数,这个析构函数不做任何事情。

#include<iostream>
using namespace std;

class Student
{
private:
    string name;
    int number;
public:
    Student(string na, int nu);//构造函数
    ~Student(); //析构函数
    void show();//输出函数
};

Student::Student(string na, int nu)//构造函数定义
{
    cout << "构造中..." << endl;
    name = na;
    number = nu;
}

Student::~Student() //析构函数定义
{
    cout << "析构中..." << endl;
}
void Student::show() //输出函数定义
{
    cout << "姓名:" << name << endl;
    cout << "学号:" << number << endl;
}
int main()
{
    Student S1("张三", 230021);
    S1.show();
    cout << "main()结束" << endl;

    return 0;
}

构造和析构的调用顺序

一般情况下,调用析构函数的次序正好与调用构造函数的次序相反,也就是最先被调用的构造函数,其对应的析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。
当然对象的构造函数和析构函数调用时机和它的生命周期是密不可分的。
下面归纳一下什么时候调用构造函数和析构函数。
(1)全局对象(生命周期:程序运行时创建,程序结束时销毁)的构造函数在所有函数(包括main函数)执行之前调用。但如果一个程序中有多个文件,而不同的文件中都定义了全局对象,则这些对象的构造函数的执行顺序是不确定的。当main函数执行完毕或调用exit函数时(此时程序终止),调用其析构函数。
(2)局部对象(在函数内定义的对象,其生命周期是进入该函数创建,函数退出结束)在进入该函数建立对象时调用其构造函数。如果函数被多次调用,则在每次建立对象时都要调用构造函数。在函数调用结束时调用析构函数。
(3)如果在函数中定义了静态(static)局部对象(生命周期是第一次进入该函数创建,程序退出时销毁),则只在程序第一次调用此函数建立对象时调用一次构造函数,在调用结束时对象并不被释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用析构函数。
(4)动态创建的对象,是调用new关键字创建函数时调用构造函数,调用delete函数销毁对象时调用析构函数。

对象数组

定义对象数组、使用对象数组的方法与基本数据类型相似,因为类本质上也是一种数据类型。在定义对象数组时,系统不仅为对象数组分配适合的内存空间,以存放数组中的每个对象,而且还会为每个对象自动调用匹配的构造函数完成数组内每个对象的初始化工作,但数组结束时会自动调用每个对象的析构函数。

声明对象数组的格式为:
类名 数组名[数组长度];

对象数组通过下标访问具体对象,访问具体对象的数据成员的格式为:
数组名[下标].数据成员;//必须有访问权限

访问具体对象的成员函数的格式为:
数组名[下标].成员函数(实参列表);//必须有访问权限

#include <iostream>
using namespace std;

class Box //长方体类
{
public:
    Box(int len = 1, int w = 1, int h = 1) ://声明有默认参数的构造函数
    length(len), width(w), height(h)
    {
        cout << "Box构造函数被调用,它的长是:"<< length << endl;
    }
    ~Box()
    {
        cout << "Box析构函数被调用,它的长是:" <<length<< endl;
    }
    int volume(); //计算体积
private:	
    int length;//长
    int width;  //宽
    int height; //高
};

int Box::volume() //计算体积
{
    return(length * width * height);
}

int main()
{
    Box a[3] =
    { //定义对象数组¦
        Box(), //调用构造函数Box,用默认参数初始化第1个元素的数据成员
        Box(10,15), //调用构造函数Box,提供第2个元素的实参
        Box(20,30,40) //调用构造函数Box,提供第3个元素的实参
	};
    cout << "a[0] 的体积是: " << a[0].volume() << endl;
    cout << "a[1] 的体积是: " << a[1].volume() << endl;
    cout << "a[2] 的体积是: " << a[2].volume() << endl;
    return 0;
}

数组对象,构造是从0下标开始往后进行,而析构是从后往前进行。

总结:数组中的每个对象都自动调用构造函数和析构函数。

对象指针

对象指针在使用之前必须先进行初始化。可以让它指向一个已定义的对象,也可以用new运算符动态建立堆对象。

定义对象指针的格式为:
类名 *对象指针 = &对象;
//或者
类名 *对象指针 = new 类名(参数);

用对象指针访问对象数据成员的格式为:
对象指针名->数据成员

用对象指针访问对象成员函数的格式为:
对象指针名->成员函数(实参列表);


#include <iostream>
using namespace std;

class Square //正方形
{
private:
    double length; //边长
public:
    Square(double len) :length(len)//构造函数
    {
    }
    void show(); //输出函数
};

void Square::show()
{
    cout << "正方形边长:" << length;
    cout << ",面积:" << length * length << endl;
}
int main()
{
    Square s(2.5);
    Square* s1 = &s;
    s1->show();
    Square* s2 = new Square{ 3.5 }; //动态创建
    s2->show();
    delete s2; //释放动态内存

    return 0;
}

this指针

this 指针是一个隐含于每一个成员函数中的特殊指针。它是指向一个正操作该成员函数的对象。当对一个对象调用成员函数时,编译程序先将对象的地址赋予this指针,然后调用成员函数。每次成员函数存取数据成员时,C++编译器将根据 this 指针所指向的对象来确定应该引用哪一个对象的数据成员。
通常this指针在系统中是隐含存在的,也可以把它显式表示出来。
例如: this指针应用。

#include<iostream>
using namespace std;

class A
{
public:
    int get() //获得成员变量的值
    {
        return i; //不使用this指针
    }
    void set(int x) //修改成员变量的值
    {
        this->i = x;//显式利用this指针访问成员变量
        cout << "this指针保存的内存地址为:" << this << endl;//输出this指针地址
    }
private:
    int i;
};
int main()
{
    A a;
    a.set(9);
    cout << "对象a所在的内存地址为:" << &a << endl;
    cout << "对象a所保存的值为:" << a.get() << endl;
    A b;
    b.set(999);
    cout << "对象b所在的内存地址为:" << &b << endl;
    cout << "对象b所保存的值为:" << b.get() << endl;
    return 0;
}

每个成员函数(包括构造函数和析构函数)都有一个this指针。它指向调用对象,如果成员方法需要使用该调用对象,则可以使用this或者*this。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值