初级C++:类成员访问权限与类默认成员函数

访问权限

这是一个原文的超链接

访问限定符

C++ 通过 public、protected、private 三个关键字来控制成员变量和成员函数的访问权限(也称为可见性),分别表示:公有的、受保护的、私有的。

class Base {
public:
    // 公有成员
protected:
    // 受保护成员
private:
    // 私有成员
}

访问权限

所谓访问权限,就是能不能使用该类中的成员。

一般地,在类的内部,无论成员被声明为哪种,都是可以互相访问的;但在类的外部,如通过类的对象,则只能访问 public 属性的成员,不能访问protected、private属性的成员。

对象(object)是类(class)的一个实例(instance)。

  • public:可以被该类中的函数、子类的函数、友元函数访问,也可以由该类的对象访问;
  • protected:可以被该类中的函数、子类的函数、友元函数访问,但不可以由该类的对象访问;
  • private:可以被该类中的函数、友元函数访问,但不可以由子类的函数、该类的对象访问。
private 关键字的作用在于更好地隐藏类的内部实现。

根据C++的软件设计规范,在实际项目开发中,类的成员变量以及只在类内部使用的成员函数,都建议声明为 private,而将允许通过对象调用的成员函数声明的 public。

成员变量声明为private,如何给它们赋值,以及获取它们的值呢?

通常需要添加两个public属性的成员函数,一个用来设置成员变量的值,一个用来读取成员变量的值。

class Date
{
public:
	Date()  /无参自定义默认构造函数,,,初始化对象
	{
		_year = 2022;
		_month = 06;
		_day = 07;
	}
	/全缺省构造函数
	Date(int year = 2022, int month = 6, int day = 7)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout<<_year<<" ";
		cout<<_month<<" ";
		cout<<_day<<endl;
	}
private:      
	int _year;			
	int _month;			
	int _day;  
}

int main()
{
	Dtae d1(1,2,3);
	d1.Print();
	return 0;
}

注意事项

  • 如果声明不写 public、protected、private,则默认为 private;
  • 声明public、protected、private的顺序可以任意;
  • 在一个类中,public、protected、private 可以出现多次,每个限定符的有效范围到出现另一个限定符或类结束为止。但为了使程序清晰,应该使每种限定符只出现一次。

*this 指针及const修饰的用法

  • C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。
  • this指针的类型:类类型* const
  • 只能在“成员函数”的内部使用
  • this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
  • 一般情况由编译器通过ecx寄存器自动传递,不需要户传递。

在这里插入图片描述


默认构造函数

类有6个默认成员函数,都是会自动生成的

  1. 默认初始化对象的属性,编译器对内置类型不会初始化,对自定义类型会调用无参的构造函数
  2. 对象实例化时,自动调用
  3. 类名,无返回值,可无参,可全参,建议写成全缺省参数
class Date
{
public:
	Date()  /无参自定义默认构造函数,,,初始化对象
	{
		_year = 2022;
		_month = 06;
		_day = 07;
	}
	/全缺省构造函数
	Date(int year = 2022, int month = 6, int day = 7)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:       /防止外人乱动我的数据
	int _year;			
	int _month;			
	int _day;  / = 6	/打补丁,给个缺省值,在没有写构造函数的情况下
}	

默认析构函数

  1. 用来清理动态开辟的内存空间,无参无返回值,类名前加~
  2. 同默认构造函数一样,只会对自定义的清理
  3. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
class tset
{
	public:
	test()
	{
		int* _a = (int*)malloc(sizeof(int));
	}
	~tset()
	{
		free(_a);
		_a = NULL;
	}
	private:
	int* _a;
}

拷贝构造函数

  1. 拷贝构造函数的参数只有一个且必须使用引用传参,无返回值
  2. 调用拷贝构造函数的场景:
    (1)一个对象以值传递的方式传入函数体 、从函数返回 ;
    (2)一个对象通过另外一个对象进行初始化。
  3. 无差别拷贝内置类型和自定义类型,实现的原理等同于memcpy,一个个字节序的拷贝—浅拷贝。
  4. 拷贝构造函数是构造函数的一个重载形式。
  5. 但对于需要用多个栈对象来说,多次拷贝同一个栈,会使得多个栈指向的是同一块儿空间,就不合适了。
class Date
{
public:
	Date(int year = 2022, int month = 6, int day = 7)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)/防止别人写错改了原来属性的数据和无限递归
	{
		tihs->_year = d._year; 
	}
	Date GetDate()
	{
		return *this;
	}
private:
	int _year;			
	int _month;			
	int _day; 
};

int main()
{
	Date d(1,2,3);
	Date d1(d);
	Date d2 =d1.GetDate();
	return 0;
}

class Stack
{
public:
	Stack(int cap = 4)
	{
		int* a = (int*)malloc(cap * sizeof(int));
	}

	/没有写拷贝构造,用默认的
	~Stack()
	{
		cout << "我就是析构函数呵呵呵" << endl;
		free(a);
	}

	void Print();

private:
	int* a;
	int top;
	int cap;
};

int main()
{
	Stack st;
	Stack st1(st);
	/此时两个指向同一块儿空间, 因为st1并没有申请开辟空间,st1只是栈区的一个变量
	return 0;
}


赋值重载函数

  • 编译器无法直接进行对自定义类型对象的加减乘除等,需要自己写一个成员函数,来实现对象之间的运算符操作,如对象的加减,比较大小等。
  • 运算符重载函数,会默认少一个参数,用隐形的this指针取代当前调用成员函数的对象,该运算符有几个操作数就需要传几个参数。还有几个不可重载的运算符,注意一下即可:.* —— :: —— sizeof ——?: ——.—— 注意以上5个运算符不能重载。
  1. 参数类型
  2. 返回值
  3. 检测是否自己给自己赋值
  4. 返回*this
  5. 一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝。
  • 特殊的赋值运算符重载函数:应具有连续赋值的功能 a=b=c… b=c表达式返回的结果是b=c后的b,b在赋给a…
Date& operator=(const Date& d)
 {
	 if(this != &d)
	 {
		 _year = d._year;
		 _month = d._month;
		 _day = d._day;
	 }
	  return *this;
 }

感言

请添加图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值