类中特殊成员(Num018)
目录
一、静态成员:
1.静态数据成员:
静态数据成员的特点:
代码示例 :
2.静态函数成员:
静态函数成员的特点:
代码示例:
使用场景:
二、单例模式
代码示例:
头文件:
同名.cpp文件:
三、 常量成员:
1.常量数据成员:
初始化类标的特点:
代码示例:
2.常量函数成员:
代码示例:
使用场景:
四、友元成员:
1.友元函数:
代码示例:
2.友元类:
代码示例:
友元特点:
使用场景:
一、静态成员:
静态成员可以在类的所有对象之间共享数据,也可以提供不依赖于类的对象的操作。静态成员是在类的整个生命周期中存在的
静态成员,指的是在C++类中声明成员时,可以加上static关键字,这样声明的成员叫静态成员
静态成员分为静态数据成员和静态函数成员两种
1.静态数据成员:
class node
{
public:
static int id;//静态数据成员定义}
int node::id=10;//不管是什么访问呢属性,静态数据成员都是在类外初始化
静态数据成员的特点:
只会被定义一次,所有对象共享这个数据
不管是什么访问属性类中声明,类外初始化
如果是公有访问属性,那么可以类外直接通过<类名::静态数据成员>访问
构造函数里面可以重新赋值
代码示例 :
#include<iostream>using namespace std;class CStudent {static int num;
public:CStudent() {num++;}int renum() {return num;}void setnum(int x) {num = x;}
};int CStudent::num;//初始化num为0,类外进行初始化int main() {CStudent s1,s2;cout << s1.renum()<< endl;cout << s2.renum()<< endl;s2.setnum(10);cout << s1.renum() << endl;cout << s2.renum() << endl;return 0;
}
2.静态函数成员:
class node
{
public:
static void fun();//在类中定义static void fun1();//类中声明
}
void node::fun1()//在类外定义
静态函数成员的特点:
访问和静态数据成员一样
静态函数成员中不能访问类中的普通成员
静态函数成员中可以使用局部变量,形参,静态成员
代码示例:
#include<iostream>using namespace std;class CStudent {int id;static int num;
public:CStudent() {num++;id = num;}static int renum() {return num;}};int CStudent::num=0;//初始化num为0,类外进行初始化int main() {cout << CStudent::renum();return 0;
}
使用场景:
1、共享数据:静态成员可以用于存储所有类的实例之间共享的数据
例如,如果一个类的所有实例需要访问相同的计数器变量,可以将该计数器声明为静态成员
2、全局数据:静态成员可以被视为类的全局变量可以在整个程序中访问静态成员,不需要创建类的实例
3、类方法:静态成员函数不依赖于类的实例,因此它们可以用于执行与特定对象无关的操作静态成员函数通常用于执行与类相关的全局任务或操作
二、单例模式
- 如资源管理器
代码示例:
头文件:
#pragma once
#include<iostream>using namespace std;
//单例模式class sing
{sing() {}//设置为私有属性static sing* p;sing(const sing&s){}//设置私有拷贝构造
public:static sing* getp() {return p;}void speak() {cout << "我必须做点什么" << endl;}//懒汉模式 再初始化时指向空,获取对象时需要先判断指针非空,若为空就new对象返回指针出去
};
sing* sing::p = new sing;//初始化是就直接new对象 饿汉模式
同名.cpp文件:
#include<iostream>
#include "sing.h"using namespace std;int main() {sing* p1 = sing::getp();sing* p2 = sing::getp();cout << p1 << " " << p2 << endl;return 0;
}
懒汉模式在高并发的时候是不安全的因为它是先判断在使用,饿汉模式是安全的它创建好了对象
三、 常量成员:
指的是在C++类中声明对象成员时可以加上const关键字
常量成员分为常量数据成员和常量函数成员,都具有常量的特点不可以修改(只读)
1.常量数据成员:
class node
{
const int id;
const int age=18; //不建议}
如果要初始化常量数据成员,通过初始化列表初始化
class node{
const int id;
int age;
node(int x):id(x),age(18)//id的值初始化为x,age初始为18,初始化列表定义{}
}
初始化类标的特点:
初始化列表也是实现类中成员数据初始化的一种方式
一些特殊情况下,数据成员的初始化只能用初始化列表的方式给数据成员赋值,而不能在构造函数中直接赋值
初始化列表必须写在构造函数的定义体后面
构造函数能对数据的初始化工作,初始化列表也可以,但是初始化列表能做的,构造函数不一定能
初始化列表的初始化顺序是按照他们在类中出现的顺序来初始化的,而不是在初始化列表中写的顺序来初始化的
代码示例:
#include<iostream>using namespace std;class node {
public:int id=10;const int age=20;node(){}//默认构造node(int x,int y):id(x),age(y)//这样赋值age是可以修改的{}
};class A {public:A() { cout << "我是A的构造" << endl; }
};class B {public:B() { cout << "我是B的构造" << endl; }
};
class C {public:C() { cout << "我是C的构造" << endl; }
};
class D {C C1;A A1;B B1;public:D(){}
};int main() {D d1;node n1(30,40);cout<<n1.age << n1.id << endl;
}
2.常量函数成员:
class node
{
int id=10;
public:
void fun()const//注意const是写在函数的后面不是前面{
id=10;//报错
}
void fun1()const;//类内声明
};
void node::fun1()const//类外实现{}
//在这个函数中,不能修改类中的数据成员(静态数据可以)
代码示例:
#include<iostream>using namespace std;class node {
public:int id = 10;const int age = 20;node() {}//默认构造node(int x, int y) :id(x), age(y)//这样赋值age是可以修改的{}void fun()const {//在函数后面加const表示不能对对象的数据进行修改int temp = 10;temp = 20;//不能修改类中的成员}void fun1()const;
};void node::fun1()const
{cout << id << " " << age << endl;
}int main() {const node n1(10, 20);cout << n1.age << n1.id<<endl;return 0;
}
使用场景:
不可修改的数据:常量成员变量用于存储在类的实例中不可更改的数据。这些常量可以是类的特定值,如PI、版本号等,或者是在类的构造函数中初始化的无需修改的数据
数据保护和封装:通过将某些成员变量声明为常量,可以防止它们被意外修改。这有助于提高类的安全性和封装性,确保只有类的特定方法才能修改数据
优化和性能:常量成员变量可以在编译时被优化。由于这些变量的值是固定的,编译器可以在必要时直接将其替换为对应的常量值,从而改善代码的性能
类的接口:常量成员函数表示这些函数不会修改任何类的成员变量。这样的函数可以被其他部分(包括常量对象和常量成员函数)使用,从而增加类的灵活性和可重用性
强制性的函数语义;声明成员函数为常量成员函数可以强制函数在不修改类的状态的情况下执行操作。这提供了一种约束,以确保函数不会产生意外的副作用。
四、友元成员:
类的特性之一就是封装,而友元就是C++为用户提供打破这种封装的手段,友元分为友元函数和友元对象
友元函数,他只是一个函数,友元函数不是类的成员,通过类对象是无法访问的,但是在这个函数中有权通过对象访问类中的所有成员
友元函数,无论声明在类中的任访问属性下都可以,不影响他的调用和访问
友元类是一个单独的类,和友元函数一样,在类中声明了一个友元类,在这个友元类中同样也可以访问该类中的所有成员
1.友元函数:
class node
{
int id=10;
friend void fun(node &n)://声明}
//定义函数,需要有类对象
void fun(node &n) {cout<<n.id<<endl;}
调用:
node n;
fun(n);//输出10
代码示例:
#include<iostream>using namespace std;class n1 {void sleep() {cout << "我在睡觉" << endl;}
public:void play(){cout << "我在玩" << endl;}friend void fun(n1& n);//友元声明
};void fun(n1& n) {n.sleep();//打破封装n.play();
}int main() {n1 nn2;fun(nn2);
}
2.友元类:
class A
{
friend class B;//声明
int id:
};
class B
{
public:
void fun(A & a)//当调用该函数的时候会访问到A的私有id
{
cout<<a.id<<endl;
}};
代码示例:
#include<iostream>using namespace std;class n1 {void sleep() {cout << "我在睡觉" << endl;}
public:void play() {cout << "我在玩" << endl;}friend void fun(n1& n);friend class n2;//友元声明
};void fun(n1& n) {n.sleep();//打破封装n.play();
}class n2 {
public:void fun(n1& n) {n.sleep();n.play();}
};int main() {n1 nn2;n2 nn1;nn1.fun(nn2);
}
友元特点:
单方向:B是A的朋友,B可以访问A的数据,A不可以访问B的数据
不传递:A是B的朋友,B是C的朋友,A和C没有朋友关系
不继承:A是B的朋友,B是C的父亲,A和C没有关系
使用场景:
1、访问私有成员:友元成员可以访问被声明为友元的类的私有成员。这样可以
在需要直接访问私有成员的情况下,避免使用公有接口或访问器函数。
2、维护类的封装性:正常情况下,类的私有成员只能被该类的成员函数访问。
但有时需要让其他类或函数能够访问私有成员,以实现特定的功能。友元成员
可以提供这种特权访问,同时仍然保持了类的封装性。
3、实现运算符重载:在运算符重载中,有时需要访问不同类的私有成员。通过
将一个类的成员函数声明为另一个类的友元成员,可以实现对私有成员的直接
访问,并且能够在运算符重载内部进行操作。
4、提升效率:有时,为了提高性能,需要直接访问类的私有成员,而不是通过
公有接口。友元成员提供了一种有效的方式,避免了公有接口的调用开销。