类和对象 I

本文探讨了C++中类的构成,包括私有、公有和保护数据成员的使用,构造函数、析构函数的作用,以及如何通过构造函数列表和拷贝构造函数实现对象初始化。重点讲解了内联函数、对象访问规则和成员初始化列表,帮助理解类的封装与数据保护原理。
摘要由CSDN通过智能技术生成

为什么有类

在C中的结构里,数据成员可以直接被访问,不安全

类的构成

类包括类名 数据成员成员函数

按访问权限划分,数据成员和成员函数又可分为公有、保护和私有3种。

一般情况下,一个类的数据成员应该声明为私有成员(保护数据)成员函数声明为公有成员

*不能在类声明中给数据成员赋初值

成员函数的定义

在类的声明中只给出成员函数的原型,而成员函数的定义写在类的外部

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

内联成员函数的定义

1.隐式声明:将成员函数直接定义在类的内部

2.显式声明:在类声明中只给出成员函数的原型,而将成员函数的定义放在类的外部

                     (在函数原型前加inline)

说明:在类中,使用inline定义内联函数时,必须将类的声明和内联成员函数的定义都放在同一个文件(或同一个头文件)中,否则编译时无法进行代码置换。

对象的定义和使用

1.可以在声明类时直接定义对象(和结构体类似)

2.也可在声明类之后定义对象

对象中成员的访问

在定义对象时,若定义的是指向此对象的指针变量,则访问此对象的成员时,不能用“.”操作符,而应该使用->“操作符

私有成员只能被类中的成员函数访问,不能在类的外部通过类的对象进行访问。

一般来说,公有成员是类的对外接口,而私有成员是类的内部数据和内部实现,不希望外界访问。将类的成员划分为不同的访问级别有两个好处

一是信息隐蔽,即实现封装,将类的内部数据与内部实现和外部接口分开,这样使该类的外部程序不需要了解类的详细实现;二是数据保护,即将类的重要信息保护起来,以免其他程序进行不恰当的修改。
 

构造函数与析构函数

构造函数

——构造函数:与类同名、无返回值类型的成员函数,在定义对象的同时被自动调用,而且只执行一次

无参构造函数:

如果创建一个类没有写任何构造函数,则系统自动生成默认的构造函数,函数为空,什么都不干

如果自己显示定义了一个构造函数,则不会调用系统的构造函数

带默认值的构造函数

有参(无默认值)的构造函数

class Score{
public:
	Score(int m, int f);  //构造函数
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};

Score::Score(int m, int f)
{
	mid_exam = m;
	fin_exam = f;
}

在使用构造函数初始化对象时:

Score op1(99, 100);
Score *p;
p = new Score(99, 100);

复制构造函数(拷贝构造函数):

是一种特殊的构造函数,当对象之间复制时会自动调用拷贝构造函数 

调用拷贝构造函数的三种情况:

  • 当用类的一个对象去初始化该类的另一个对象时;
  • 当函数的形参是类的对象,调用函数进行形参和实参结合时;
  • 当函数的返回值是对象,函数执行完成返回调用者时。

若类中没有显示定义拷贝构造函数,则系统会自动生成默认拷贝构造函数

拷贝构造函数是一种特殊的构造函数,具有单个形参,该形参(常用const修饰)是对该类型的引用

当类中有一个数据成员是指针时,或者有成员表示在构造函数中分配的其他资源,必须显式定义拷贝构造函数

class Test
	{
	public:
		Test(){
			x = 0;
			y = 0;
			p = new int(10);
		}
	
		Test(const Test& t)
		{
			x = t.x;
			y = t.y;
			p = new int(10);
			*p = *(t.p);
		}
	
		~Test(){
			assert(p != NULL);     // assert()作用是如果他的条件返回错误,则终止程序执行 
			delete p;
		}
	
		int get_x(){return x;}
		int get_y(){return y;}
	private:
		int x;
		int y;
		int* p;
	};
	
	int main()
	{
		Test t1;
		Test t2(t1); 
    }

此时t1与t2的p各自指向一段内存空间,但他们指向的内容相同,这就是“深拷贝” ,若不重写拷贝构造函数,在使用t1复制t2时,进行的是浅拷贝,只是将成员的值进行赋值。此时,t1.p = t2.p, 即两个指针指向了堆里的同一个空间。这样,析构函数会被调用两次。

成员初始化列表

在声明类时,对数据成员的初始化工作一般在构造函数中用赋值语句进行。此外还可以用成员初始化列表实现对数据成员的初始化。 

class A{
private:
	int x;
	int& rx;
	const double pi;
public:
	A(int v) : x(v), rx(x), pi(3.14)    //成员初始化列表
	{	}
	void print()
	{
		cout << "x = " << x << " rx = " << rx << " pi = " << pi << endl;
	}
};

 

析构函数


——析构函数:它执行与构造函数相反的操作,通常用于撤销对象时的一些清理任务,如释放分配给对象的内存空间等

析构函数与构造函数名字相同,但它前面必须加一个波浪号(~)。
析构函数没有参数和返回值,也不能被重载,因此只有一个。
当撤销对象时,编译系统会自动调用析构函数。

class Score{
public:
	Score(int m = 0, int f = 0);
	~Score();       //析构函数
private:
	int mid_exam;
	int fin_exam;
};

Score::Score(int m, int f) : mid_exam(m), fin_exam(f)
{
	cout << "构造函数使用中..." << endl;
}

Score::~Score()
{
	cout << "析构函数使用中..." << endl;
}

析构函数什么时候被调用

1.如果定义了一个全局对象,则在程序流程离开其作用域时,调用该全局对象的析构函数。

2.如果一个对象定义在一个函数体内,则当这个函数被调用结束时,该对象应该被释放,析构函数被自动调用。

3.若一个对象是使用new运算符创建的,在使用delete运算符释放它时,delete会自动调用析构函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值