从零开始学习C++第六篇:特殊函数和成员

一、对象成员的初始化

对象成员构造函数的调用顺序取决于这些对象成员在类中的说明顺序。

如当先建立A类对象时,先调用对象的构造函数,初始化对象成员,然后再调用A类的构造函数,初始化A类的其它成员。

析构函数则是顺序相反。

#include <iostream>
using namespace std;
class object{
private:
	int val;
public:
//	object(){
//		val=0;
//		cout<<"不带参构造函数"<<endl;
//	}
	object():val(0){
		cout<<"object 不带参构造函数"<<endl;
	}
	object(int i):val(i){
			cout<<"object 带参构造函数"<<val<<endl;
	}
	~object(){
			cout<<"object 析构函数"<<val<<endl;
	}

};
class container{
private:
	object one;
	object two;
	int data;
public:
	container():data(0){
		cout<<"container 不带参构造函数"<<endl;
	}
	container(int i,int j,int k);
	~container(){
		cout<<"container 析构函数"<<data<<endl;
	}

};
container::container(int i,int j,int k):two(i),one(j){
		data=k;
		cout<<"container 带参构造函数"<<data<<endl;
	}

int main() {
	container obj;
	container anobj(5,6,10);
	return 0;
}

运行结果:

object 不带参构造函数
object 不带参构造函数
container 不带参构造函数
object 带参构造函数6
object 带参构造函数5
container 带参构造函数10
container 析构函数10
object 析构函数5
object 析构函数6
container 析构函数0
object 析构函数0
object 析构函数0

先为成员对象one调用不带参构造器,然后为two,再然后是对象obj,对象anobj同理,然后析构顺序相反。

二、静态成员

static修饰符

在c++中,静态成员是属于整个类而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏(相比于全局变量)的原则,保证了安全性还可以节省内存。 

类的静态成员,属于类,也属于对象,但终归是属于类。

静态成员为该类内所有成员共享。类中的任何成员函数都可以访问。

静态对象调用一次构造器,一次析构函数。

三、友元函数

有时两个概念上相似的类要求其中一个类可以无限制的存取另一个类的成员变量。

友元函数可以直接访问对象的私有成员;可以根据需要,通过使用友元增加类的接口。

/*类本身的友元函数    求两点距离*/
#include <iostream>
#include <math.h>
using namespace std;
class Point{
private:
	float x,y;
public:
	Point(float xi,float yi){
		x=xi;
		y=yi;
	}

	float getX() {
		return x;
	}

	float getY() {
		return y;
	}
	friend float distances(Point&,Point&);//声明友元函数
};

float distances(Point& a,Point& b){
	float dx=a.x-b.x;          //可以访问私有变量x,y
	float dy=a.y-b.y;
	return sqrt(dx*dx+dy*dy);
}

int main() {
	Point a(3.5,5.5);
	Point b(2.3,5.6);
	cout<<"两点之间距离为:"<<distances(a,b)<<endl;
	return 0;
}

运行结果:

两点之间距离为:1.20416

将一个类中的成员函数用作另一个类的友元函数

/*在One中定义一个Two的友元函数,修改Two对象的成员数值*/
#include <iostream>
using namespace std;
class Two;
class One{
private:
	int x1;
public:
	One(int a){
		x1=a;
	}
	void ad(Two& );

	int getX1() const {
		return x1;
	}
};


class Two{
private:
	int x2;
public:
	friend void One:: ad(Two&);
	Two(int b){
		x2=b;
	}
	int getX2()  {
		return x2;
	}
};

void One::ad(Two& r){
	r.x2=x1;
}

int main() {
	One a(5);
	Two b(8);
	cout<<"One:"<<a.getX1()<<" Two:"<<b.getX2()<<endl;
	a.ad(b);
	cout<<"One:"<<a.getX1()<<" Two:"<<b.getX2()<<endl;
	return 0;
}

运行结果:

One:5 Two:8
One:5 Two:5

一个类作为另一个类的友元函数

#include <iostream>
using namespace std;
class Two{
private:
	int y;
public:
	Two(int a){y=a;};
	friend class One;

	int getY()  {
		return y;
	}
};
class One{
private:
	int x;
public:
	One(int a,Two& r,int b){
		x=a;
		r.y=b;
	}
};
int main() {
	Two A(10);
	cout<<A.getY()<<endl;
	One b(5,A,6);
	cout<<A.getY();
	return 0;
}

运行结果:

10
6

四、const对象

在使用C++语言开发中,如果我们希望某一个对象在定义之后不被错误的修改,我们可以将这个对象声明为const对象,这样这个对象的数据成员就不可以被更改。

1.常量成员

常量成员包括:常量数据成员、静态长数据成员、常引用。

常引用传入的时地址,不会改变实参的值。

#include <iostream>
using namespace std;
class Base{
private:
	int x;
	const int a;//常数据成员只能通过初始化列表来获取初值
	static const int b;//静态常数据成员
	const int& r;//常引用只能通过初始化列表来获取初值,
public:
	Base(int,int);
	void Show(){
		cout<<x<<","<<a<<","<<b<<","<<r<<endl;
	}
	void Display(const double& r){
		cout<<r<<endl;
	}
};
 const int Base::b=125;
Base::Base(int i,int j):x(i),a(j),r(x){}

int main() {
	Base A(25,13);
	A.Show();
	A.Display(3.36);//常引用作为函数参数,不会改变r的值
	return 0;
}

运行结果:

25,13,125,25
3.36

2.常成员函数

定义格式:类型标识符  函数名(参数列表) const;

类型标识符  类名::函数名 (参数列表)const { //函数体 }

const对象只能调用它的const成员函数。

#include <iostream>
using namespace std;
class Base{
private:
	float a,b;
	const float c;//定义一个常量数值
public:
	Base(float x,float y,float z):c(z){
		a=x;
		b=y;
	}
	void show(){
		cout<<"a:"<<a<<" b:"<<b<<" c:"<<c<<endl;
	}
	void show()const{
		cout<<"a:"<<a<<" b:"<<b<<" const c:"<<c<<endl;
	}
};
int main() {
	Base A(3.2,4.5,6.6);
	A.show();
	Base const B(3.2,4.5,6.6);//定义一个常量对象,只能调用它的const成员函数
	B.show();
	return 0;
}

运行结果:

a:3.2 b:4.5 c:6.6
a:3.2 b:4.5 const c:6.6

五、指针和类

指向类对象的指针

#include <iostream>
using namespace std;
class Test{
private:
	int x;
	float y;
public:
	Test(int a):x(a){}
	Test(int a,float b):x(a),y(b){}

	int getX(){
		return x;
	}

	float getY() {
		return y;
	}
};
int main() {
	Test a[2]={2,4};//调用只有一个参数的构造函数进行初始化,所以只有x的值
	Test *p;//定义指向Test类的指针
	Test b[2]={Test(2,2.3),Test(3,5.6)};
	p=b;
	for(int i=0;i<2;i++){
		cout<<"a["<<i<<"].x:"<<a[i].getX()<<"  a["<<i<<"].y:"<<a[i].getY()<<endl;
	}
	for(int i=0;i<2;i++){
		cout<<"b["<<i<<"].x:"<<p->getX()<<"  b["<<i<<"].y:"<<p->getY()<<endl;
	}
	return 0;
}

运行结果:

a[0].x:2  a[0].y:9.09139e-039
a[1].x:4  a[1].y:1.60855e+032
b[0].x:2  b[0].y:2.3
b[1].x:2  b[1].y:2.3

指向类成员函数的指针

例如:指向类A中的参数类型列表为list,返回值为type成员函数的指针声明:

type(A::*pointer)(list)

#include <iostream>
using namespace std;
class A{
private:
	int val;
public:
	A(int a):val(a){}
int xj(int a){
		return val+a;
	}
};
int main() {
	A s1(15);
	A *p1=&s1;//类的指针
//	cout<<(p1->xj)(10);//指向类对象的指针不能直接调用成员函数
	
	int(A::*p2)(int);//声明指向A成员函数的指针p2
	p2=A::xj;//指向的具体函数
	
	cout<<(s1.*p2)(15)<<endl;
	cout<<(p1->*p2)(15)<<endl;
	return 0;
}

运行结果:

30
30

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值