第5节课:9.6:静态友元常量成员
一、类中的静态成员(静态数据成员和静态函数成员)
1.是什么
在c++声明中,可以在前面加上static关键字,将该成员声明为静态成员
静态成员分为静态数据成员和静态函数成员两种
2.定义
static int a;
static void change_a();
在code部分举个栗子:
3.静态数据成员的特性:
(1).该成员属于类但是不属于类的对象(但是类对象可以访问)
(也就是说类的对象还没存在,静态成员已经存在了);
(2).为所有对象所共享,只有单独的一份内存。生命周期:在main之前就已经开始了,直到main函数结束
(也就是说类的对象还没存在,静态成员已经存在了);
(3).访问(公有属性)
1.可以被类对象访问
2.类中的普通函数可以访问
3.类作用域符可以访问(特殊性:只有静态成员才可以这样用,因为他不属于类的对象)
(4).必须在类外进行初始化
(不需要加上static)
class test
{
public:
static int c;
};
//int test::c = 1;
4.静态函数成员特性:
question:萝卜老师,那个静态函数成员是存储在代码区,不是静态全局区,static只是改变了函数的一些特性而已吧
(1).访问和静态数据成员相同
(2).该函数只能访问静态成员(数据和函数),不可访问类内其他成员(生命周期不同)
在函数内可以使用局部变量(在调用该函数时为局部变量在栈内开辟空间),静态成员
(3).不属于对象,属于类
code:示例;
#include <stdio.h>
class test
{
private:
int a;
public:
int b;
static int c;
public:
test();
~test();
void change_c();//类普通成员
static void change_c1();//静态函数成员
static void change_c2();//静态函数成员
};
int test::c = 1;
void test::change_c2()
{
c++;
/*a = 1;
change_c();*/
}
void test::change_c1()
{
c = 100;
}
void test::change_c()
{
c++;
}
test::test(){ a = 1; }//无参构造
test::~test(){}
int main()
{
test obj;
test obj1;
printf("%d\n",obj1.c);//类对象可以访问
printf("%d\n",test::c);//静态成员属于类,通过类作用域符可以访问(公有)
obj.change_c();//类普通成员可以访问
printf("%d\n", obj1.c);//静态数据成员独一份内存
printf("%d\n",obj.c);
//test::b = 1;//非静态成员只能通过对象访问;
return 0;
}
二、static的5种方法
1.类中的静态数据成员
2.类中的静态函数成员
3.修饰全局变量
区分全局作用域、文件全局作用域、块作用域(?复习该知识点c的,以及作用域和生命周期的差别)
通过static修饰全局变量:内存在全局数据区(该变量的作用域只能是文件作用域)
static int a1 = 0;(文件)
extern int a2;(项目作用域也就是全局作用域)
int a3;(默认文件全局)
4.通过static修饰块作用域变量
该变量的作用域未修改,但是变量内存在全局数据区
void fun()
{
static int a = 0;
a++;
printf("%d "a);//a不是在栈区而是在全局数据区,不会在作用域结束后释放(???考虑一下生命周期)
}
for(int a = 0;a<10;a++)
{
fun();
}
printf("%d",a);//error:作用域为块作用域,访问不了
5.函数默认是项目作用域,通过static修饰后为文件全局作用域
本来函数定义好了后,声明导入头文件,所有文件头都可以使用。
如果加了static后,只能在该文件里用,一种保护措施
6.补充:生命周期和作用域
1.普通全局变量
生命周期和作用域
普通全局变量 | 静态全局变量 | 普通局部变量 | 静态局部变量 | |
---|---|---|---|---|
生命周期 | 程序开始到结束 | 程序开始到结束 | 当前语块 | 从程序开始到程序结束 |
作用域 | 文件作用域(有extern为项目作用域) | 文件作用域 | 当前语块 | 当前语块 |
三、单例模式
1.是什么?
是一种软件开发模式
2.定义?
#include <stdio.h>
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
class CA
{
private:
int a;
CA(int i);
CA(const CA& other);
static CA* p;//为什么是静态的呢?因为静态的可以初始化,
//如果不是静态的只能通过构造函数来初始化(这种情况下就无法完成初始化工作)
public:
static CA* GetObj();
void print();
};
//静态数据成员初始化
CA* CA::p = new CA(1);//只能创建一个对象
CA* CA::GetObj()
{
return p;
}
CA::CA(const CA& other)
{
;
}
CA::CA(int i)
{
a = i;
}
void CA::print()
{
cout <<"我是一个单例模式\n"<<p->a << endl;
}
int main()
{
//CA obj(1)
//CA* p = new CA(1);//只能够创建唯一一个对象
//CA* pt = CA::p;//私有成员无法访问,只能够通过接口来访问
CA* pt = CA::GetObj();
pt->print();
return 0;
}
四、友元成员
1.是什么?
类的特性之一是封装,而友元则是提供给用户用于打破封装的手段
分为友元函数和友元类
2.定义?
1.友元函数的定义
code部分
2.友元类的定义
code部分
3.特性:
(1)友元函数
1.友元函数无论实在类中定义还是类外定义都不是类的成员,通过类对象无法访问
2.在友元函数中可以访问对象的所有成员(属性和方法):最特殊的可以访问私有的
(2)友元类
3.友元类是单独的一个类,在声明之后,该类的成员函数通过对象可以访问对象类的私有成员。
其实就是和友元函数的访问特性差不多
关键:是通过对象去访问私有成员哦
4.单向性:A是B类的友元类但是B不是A的友元类
5.不继承:以后讲解
6.不传递:
#include <stdio.h>
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
class CB;
class CA
{
int a;
void printf();
public:
int c;
static int b;
public:
CA();
CA(const CA& other);
public:
void speak(CB const& obj);//CB中有friend class CA;那么CB的对象就可以访问obj的私有成员了(本来是无法访问的)
friend void print(CA& objx);//CA的友元函数
};
class CB
{
friend class CA;
int a;
void print() const;
public:
int b;
CB();
};
int CA::b = 0;
CA::CA()
{
a = 1;
b = 2;
c = 3;
}
CA::CA(const CA & other)
{
;
}
void CA::speak(const CB & obj)//void speak(const CB& obj);
{
cout << "我是CA的函数可以通过CB类对象访问CB的私有成员" << endl;
obj.print();
}
void CA::printf()
{
cout << "我是CA的私有成员!!!" << endl;
}
void print(CA& objx)
{
cout << "我是CA的友元函数,可以通过CA对象访问CA的私有成员" << endl << "公有静态数据成员 b = " << CA::b << endl << "公有数据成员 c = " << objx.c << endl << "私有数据成员 a = " << objx.a << endl;//可以对象访问私有数据成员和函数成员了
objx.printf();
}
void CB::print()const
{
cout << "我是CB的私有函数成员\n";
}
CB::CB()
{
a = 10;
b = 20;
}
int main()
{
CA obj;
CB obj1;
print(obj);//CA的友元函数
obj.speak(obj1);//CA的公有函数成员;
return 0;
}
//出错原因:const CB & obj
//把因为是const obj 所以把this转化为 const this,从而只能调用const函数
五、常量成员
1.是什么?
c++中,在类中加上const修饰成员(可以是成员函数和数据成员)
2.定义?
(1).常量数据成员(成员初始化列表)
(2).常量函数成员
code部分示例
3.常量数据成员特性:
常量数据成员,不能在构造函数里面直接赋值,只能在成员初始化列表内赋值
4.成员初始化列表(特殊的成员初始化)
1.在构造函数定义后面:c(123),b(1)之间用逗号隔开
2.既可以对const 成员初始化也可以对普通数据成员初始化
3.初始化的顺序:数据成员在类中的声明顺序来调用
4.在类中声明的时候不用加上列表,在定义的时候才要加
5.构造函数和初始化列表的比较
构造函数能够做的初始化列表都能够做,但是初始化列表能够做的,构造函数不一定能够做
构造函数是不是相对于成员初始化列表没有优势(构造函数是不是可以不用写?)
(1).成员初始化列表要写在构造函数之后
(2).构造函数虽然给数据成员赋值的时候没有初始化成员列表那么高效但是,构造函数有函数体
(3).构造函数可以有重载而且可以有拷贝构造,实现深拷贝,而初始化成员列表不可以
(4).创建一个对象也需要构造函数
code:
#include <stdio.h>
class CA
{
int a;
int const b;
public:
CA();
public:
int get_A()const;
int get_B()const;
};
CA::CA() :b(1)
{
a = 1;
}
int CA::get_A()const
{
return a;
}
int CA::get_B()const
{
return b;
}
int main()
{
CA obj;
printf("%d ",obj.get_B());
return 0;
}
6.常量函数成员特性:
1.this可以访问的都不能被修改
#include <iostream>
#include <stdio.h>
using std::cin;
using std::cout;
using std::endl;
class CA
{
int a;
const int c;
public:
int b;
CA(int i,int j);
~CA();
void print()const;
};
CA::CA(int i,int j) :c(i)
{
a = j;
b = i;
}
CA::~CA()
{
;
}
void CA::print()const//谁调用的,就会有一个this指针
{
this->b++;//不可修改
cout << this->b << endl;
}
int main()
{
CA obj1(1,2);
obj1.print();
return 0;
}
六、常量对象
1.是什么:
在对象前加const修饰
2.定义:
CA const obj;
3.使用:
1.常量对象只能调用常量函数成员,普通函数成员调用不来(因为普通函数成员的会修改对象的值)
2.对象所有成员都不可以被修改