欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > 类与对象(三)

类与对象(三)

2024/11/30 11:22:58 来源:https://blog.csdn.net/weixin_50512050/article/details/117783469  浏览:    关键词:类与对象(三)

类的其他成员

常成员
静态成员
友元

常成员

常数据成员

常数据成员是指数据成员在实例化被初始化后约束为只读

const int m;
static const int b;   //静态常数据成员,只能初始化,不能赋值;
常对象

常成员函数是指成员函数的this指针被约束为指向常量的常指针,函数体内不能修改数据成员的值。
在这里插入图片描述

常成员函数

调用的时候有个一一对应关系

int main()
{R a(5,4);
a.print();//调用void print()
const R b(20,52);
b.print();//调用void print() const
}

常成员函数不能更新对象的数据成员
也不能调用该类中的非常成员函数(下方代码可说明)
在这里插入图片描述

#include<iostream>
using namespace std;
class R
{
public:R(int r1, int r2) { R1 = r1; R2 = r2; }void print () const;void print(){cout << "a" << endl;}
private:int R1, R2;
};
void R::print() const
{cout << R1 << ":" << R2 << endl;print();//由于无论是不是常成员函数,因为它俩同名,又因为常成员函数里不能调用非常成员函数,同上。//因此这儿应该是一直在调用该非常成员函数,在无穷递归
}
int main()
{const  R a(5, 4);a.print();//调用void print() constreturn 0;
}

常对象只能调用常成员函数(上方代码可说明)
但是常成员函数也可以被普通对象来调用(下方代码可说明)

当函数中只有常成员函数的时候
即使是普通对象
也可调用常成员函数
#include<iostream>
using namespace std;
class R
{
public:R(int r1, int r2) { R1 = r1; R2 = r2; }void print () const;
private:int R1, R2;
};
void R::print() const
{cout << R1 << ":" << R2 << endl;
}
int main()
{R a(5, 4);a.print();//调用void print() constreturn 0;
}

在这里插入图片描述

#include<iostream>
using namespace std;
class A
{int a;
public:void f(int m)const;
};
void A::f(int m)const
{m = a;//只有这个是对数据成员的读操作,其他都是写操作//a = m; 报错//cin>>a;//m=a++;
}

静态成员

函数声明好像一直都还挺无所谓的,就算在函数体里说明了,在不在类的花括号外写,好像没什么太大区别。
类成员冠以static声明时,称为静态成员。
静态数据成员为同类对象共享
静态成员函数与静态数据成员协同操作。
静态成员函数主要是用来修改静态成员的。
把一个类的成员说明为 static 时,这个类无论有多少个对象创建,这些对象共享这个 static 成员。
静态成员局部于类,它不是对象成员。

静态数据成员

在这里插入图片描述
在类的声明中仅仅对静态数据成员进行引用性说明,必须在文件作用域的某个地方使用类名限定进行定义性说明,这时也可初始化。
在类的声明中只能声明静态成员数据的存在。由于类的声明是抽象的,静态成员数据的初始化需要在类的外部进行,通过类名对它进行访问。

#include<iostream>
using namespace std;
class a
{
public:a();~a();int x, y;static int num;void print();
};
int a::num;//如果把这一行注释掉,那么会出现下方的报错
//这一块儿的静态数据成员在类外的再次定义是必须要有的,就算不进行初始化,也要有定义,否则就报错
a::a()
{cout << "contructed" << endl;
}
a::~a()
{cout << "deleted" << endl;
}
void a::print()
{cout << x << endl << y << endl << num << endl;
}
int main()
{a b1;b1.x = 3;b1.y = 4;b1.num = 5;b1.print();return 0;
}

在这里插入图片描述

在这里插入图片描述
如果创建了两个类对象,a和b,它们都有共同的数据成员num,先令a.num=1;再令b.num=2;然后分别输出a.num和b.num;结果是2 2。
私有静态数据成员可以借用公有成员函数间接使用与改变;
公有静态数据成员可以直接使用。
两种不同的访问方式:
在这里插入图片描述

静态成员函数

成员函数可分为静态成员函数和非静态成员函数。
因此,并非所有的成员函数都有this指针,像静态成员函数就没有,尽管它也叫成员函数。
静态成员函数数冠以关键字static。
静态成员函数没有this指针,但是是成员函数(参照上面几句话),只能对静态数据操作。
在类外调用静态成员函数用 “类名 :: ”作限定词,或通过对象调用。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

友元

由于一个对象的私有成员只能通过成员函数访问,定义公有数据又破坏了信息的隐蔽性。
友元是对类操作的辅助手段。友元能够引用类中本来被隐蔽的信息。
C++提供了一种辅助手段,定义类的友元。友元可以访问类的所有成员,包括私有成员。友元可以是一个函数或者是一个类。
使用友元目的是基于程序的运行效率;
运算符重载的某些场合需要使用友元。
存在非对称性非传递性
缺少的代码,友元函数对应友元函数,友元类对应普通成员函数。

友元函数

友元函数不是类的成员,属于非成员函数, 一般通过参数访问对象的私有成员。

#include<iostream>
using namespace std;
class line;
class box
{
private:int color;int upx, upy;int lowx, lowy;
public://这儿缺了一个友元函数的声明//导致下面的友元函数的声明就只能访问line类的私有成员//因为它只是line类的友元函数//所以看到下面友元函数的定义里有box的私有函数,就明白这儿缺个友元void set_color(int c) { color = c; }void define_box(int x1, int y1, int x2, int y2){upx = x1; upy = y1; lowx = x2; lowy = y2;}
};
class line
{
private:int color;int startx, starty;int endx, endy;
public:friend int same_color(line l, box b);void set_color(int c) { color = c; }void define_line(int x1,int x2,int y1,int y2){startx = x1; starty = y1; endx = x2; endy = y2;}
};
int same_color(line l, box b)
{if (l.color == b.color) return 1;return 0;
}

友元类

若F类是A类的友元类,则F类的所有成员函数都是A类的友元函数。
友元类通常设计为一种对数据操作或类之间传递消息的辅助类。
这种非对称性,可以用一个例子来说明:

#include<iostream>
using namespace std;
class A
{/*friend class B;*/
public:void Display(){cout << x << endl;}
private:int x;
};class B
{
public:void Set(int i);void Display();
private:A a;
};
void B::Set(int i)
{a.x = i;//报错,不能访问a的私有成员x,即使a是B的类类型数据成员对象//因为像在主函数里不能访问a的私有成员对象一样,// **即使是在B类的函数体里这对于A类对象a来说都属于类外**}
void B::Display ()
{a.Display ();
}
这么干就会报错,在没有继承的情况下,
友元的存在,使B成为A的友元,也就使B可以访问A的任何成员。

#include <iostream>
#include <cmath>
using namespace std;
class Point
{
private:double x, y;//这儿缺了一个友元类//friend class Line
public:Point(double i = 0, double j = 0){x = i; y = j;}Point(Point& p){x = p.x; y = p.y;}
};
class Line
{
private:Point p1, p2;//
public:Line(Point& xp1, Point& xp2) :p1(xp1), p2(xp2) {}double GetLength();
};
double Line::GetLength()
{double dx = p2.x - p1.x;double dy = p2.y - p1.y;return sqrt(dx * dx + dy * dy);
}
void main()
{Point p1, p2(6, 8);Line L1(p1, p2);cout << L1.GetLength() << endl;
}

在这里插入图片描述

类的包含

称为has-a
是一种软件重用技术,在定义一个新类的时候,通过编译器把另一个类“抄写”进来,这样 程序员就不用再编写一模一样的代码,只要添加新的功能代码即可。
在这里插入图片描述
这儿之所以不报错,是因为虽然A a是A类类对象,但是x在A类里的访问特性是公有的,所以也就是说,B类相当于A类是在类外,因为这个公有的特性,所以即使这儿不用友元,也是可以访问不会报错,前面讲友元的时候要用,友元类是因为,x是私有成员,所以本类中的数据成员是公有还是私有要看清吧!
但是,要在类的包含里面实际使用a的数据成员,就需要初始化式来对数据成员进行一个初始化,可以是复制构造函数,也可以是普通的构造函数。
格式大致如下:

class A
{
public:
A(int x):a(x){}
int a;
};
class B
{
public:
B(int x,int y):aa(x)//类的对象名后面的形式和本类中构造函数的格式大致相同,括号里面的参数都是一样的
{
b=y;
}
void out()
{
cout<<"aa="<<aa.a<<endl<<"b="<<b<<endl;}
private:int b;A aa;
};
int main()
{
B objB(3,5);
objB.out();
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com