C++类与对象(下)

在经过前面两篇文章的学习,我们已经对类和对象有了一个比较全面的认识了,接下来让我们学习类与对象的最后一节内容。

一.再探构造函数

在上一篇文章中,我们学习了类内的一些成员函数,现在我们来更深入的学习构造函数。

C++引入了一种新的构造函数初始化方法——初始化列表,在函数后加冒号,然后成员变量间用逗号隔开。

Person(int age,int weight):_age(age),_weight(weight){}

注意

每个成员变量只能在初始化列表初始化一次,我们可以把初始化列表认为是成员变量定义的地方。

class Person
{
public:
	int _age;
	int _hight;
	int _weight;
	Person(int age,int hight,int weight):_age(age),_hight(hight),_weight(weight){}
};
引⽤成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进⾏初始
化,否则会编译报错。
class Person
{
public:
	int _age;
	int _hight;
	int _weight;
	int& ret;
	const int* aa;
	Person(int age, int hight, int weight) :
		_age(age),
		_hight(hight),
		_weight(weight),
		ret(age),
		aa(nullptr)
	{}
};

C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显⽰在初始化列表初始化的
成员使⽤的。
class Person
{
public:
	int _age=10;
	int _hight=70;
	int _weight=155;
	Person(int age, int hight, int weight) :
		_age(age),
		_hight(hight)
	{}
};

初始化列表的初始化顺序与声明顺序有关,如果一个成员变量的声明在最后一个,即使在初始化列表中它排在第一个位置也不会初始化,而是等待其他成员变量初始化后才初始化它。
这里我们举一个反例来看,输出结果可以证明红字,如果根据初始化列表的顺序来初始化成员变量,那么a和b的值都应该为2才对,但二者的值都为1,所以初始化列表是根据成员变量的声明顺序来初始化成员变量的。
#include <iostream>
using namespace std;
class Person
{
public:
	int a = 1;
	int b = 1;
	Person(){}
	Person(int a, int b):b(2),a(b)
	{}
	void Printf()
	{
		cout << a << "   " << b << endl;
	}
};
int main()
{
	Person p;
	p.Printf();
}
//输出结果为1    1

在使用参数化列表时,如果参数列表内部有自定义类型,需要注意自定义类型是否至少有一个构造函数,否则就会报错

下面为正确的代码,在A类内写了一个有参构造函数。

#include <iostream>
using namespace std;
class A
{
public:
	int c;
	A(int cc):c(cc){}
};
class Person
{
public:
	int a = 1;
	int b = 1;
	A cc;
	Person(int a, int b):a(10), b(10),cc(10)
	{}
	void Printf()
	{
		cout << a << "   " << b << endl;
	}
};
int main()
{
	Person p(20, 30);
}

二.隐式类型转换

C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。
class Person
{
public:
	int a = 1;
	int b = 1;
	Person(int aa):a(aa){}//如果没有这个构造函数Person p=10就会报错
	Person(int a, int b):a(10), b(10)
	{}
	void Printf()
	{
		cout << a << "   " << b << endl;
	}
};
int main()
{
	Person p = 10;
}

构造函数前⾯加explicit就不再⽀持隐式类型转换

三.static成员

静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。它不能给缺省值初始化,也不能用初始化列表,它在静态区中,不会走初始化列表。

用static修饰的成员变量,需要在类内声明,类外初始化。

用static修饰的函数叫做静态成员函数,不可以访问非静态成员变量,因为没有this指针,非静态成员函数可以访问静态成员变量和函数。

静态成员和静态成员函数的访问都受类作用域限定符的影响,它们都是类的成员。

class A
{
public:
	//static int a=10;不可给缺省值
	static int a;
	int b;
	static void GetA()
	{
		//b = 10;不可访问非静态成员变量
		a = 10;//可以访问
	}
	void Get()
	{
		//非静态成员函数可以访问静态成员变量
		b = 10;
		a = 10;
	}
	//不能用初始化列表初始化静态成员变量
	//A(int b):a(10),b(20){}
	//A(int b) : b(20) {}
	A() { ++a; }
	A(int b) { ++a; }
	A(const A& aa) { ++a; }
	~A() { --a; }
	int GetACount() { return a; }
};
int A::a = 0;
int main()
{
	A aa;
	cout << aa.GetACount() << endl;
	A aa1(10);
	cout<<aa1.GetACount()<<endl;
	A aa2(aa1);
	cout<<aa2.GetACount() << endl;
}
//输出结果为
1
2
3

四.友元

友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或者类
声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯。
友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元,但是B类不是A类的友元。
友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不是B的友元。

class A{};
class B
{
	friend A;
};

五.内部类

如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独⽴的类,跟定义在
全局相⽐,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。
内部类默认是外部类的友元类。
从输出结果可以看出在计算类的大小时不会计算内部类。

六.匿名对象

只用类型(实参)定义出来的对象叫做匿名对象,相⽐之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象,匿名对象的生命周期很短,使用完就会被销毁。

文章就到这里了,如果你觉得写的还不错的话,请点赞收藏支持一下,如果有写错的地方,还请批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值