C++静态成员变量初始化和赋值

1.背景

有这样一套会话机制,CSession为会话对象,CSessionManager为会话管理类,在CSession会话需要销毁时,CSession主动发送消息给CSessionManager销毁session。同时CSession是一个基类,子类通过继承CSession实现不同的session处理。

实现主要考虑三个方面(创建、处理、销毁):

  1. 通过不同的server创建不同的session会话;
  2. 子类通过CSession提供的虚函数接口实现多态;
  3. 通过消息对象指针发送消息给CSessionManager销毁session;

问题卡在session的销毁:

CSessionManager通过消息队列模板类创建消息对象,保存消息对象指针信息,并且有一个线程专门接收该对象发送的消息。那么CSession会话类也需要知道和保存消息对象指针。

先前有类似情况,消息对象指针是通过构造传参保存下来的。但现在CSession作为一个基类(要被继承),显然通过构造传参是非常不合理的,并且我希望CSession只保存一份消息对象指针(static成员变量),提供唯一 一个发送消息的接口给子类。

大致代码如下:

typedef struct
{
	int connfd;
	int keepfd;		/*是否保留fd:1-是,其他-否*/
}SocketSessionExp;

//session会话基类(HttpSession、RtspSession继承该类)
class CSession
{
	friend class CSessionManager;
	public:
		CSession();
		virtual ~CSession();
	protected:
		static void sendMessage(SocketSessionExp &expMessage);//希望CSession对象和子类能通过这个唯一接口发送消息给CSessionManager销毁该CSession会话
	private:
		static TMessageQue<SocketSessionExp> *m_exception_msq;//TMessageQue为消息队列模板类
}

//会话管理类
class CSessionManager
{
public:
	static CSessionManager* instance();		//单健类
private:
	CSessionManager();
	{
		m_exception_msq = new TMessageQue<SocketSessionExp>();
		CSession::m_exception_msq=m_exception_msq;
	}
	~CSessionManager();//不是重点未给出
private:
	static TMessageQue<SocketSessionExp> *m_exception_msq;//在构造函数中new一个类对象
	std::map<int,CSession*>			m_sessionMap;
}

该模块编译时没报错,链接时报错提示:

undefined reference to `Network::CSession::m_exception_msq'

2.试错

CSessionManager是CSession的友元类,可直接访问CSession的私有成员和保护成员。也尝试通过函数、局部CSession等方式来完成m_exception_msq的赋值,均报错。

3.分析与百度

class CSession
{
	friend class CSessionManager;
	public:
		CSession();
		virtual ~CSession();
	private:
		static TMessageQue<SocketSessionExp> *m_exception_msq;//TMessageQue为消息队列模板类
}

分析-有用信息:

  1. 在如上代码中,m_exception_msq只是声明,并没有定义和初始化。
  2. “undefined reference to”是未定义……;
  3. 项目中有地方使用静态变量的地方都在.cpp文件上方进行了初始化(实际是定义–>初始化)。

分析推测:应该是m_exception_msq未定义。

在.cpp文件中添加如下代码:

//xxx.cpp
TMessageQue<SocketSessionExp>* CSession::m_exception_msq=NULL;

编译成功、链接成功、通过打印信息也看到CSession::m_exception_msq在CSessionManager构造中完成了赋值,问题解决了。

这里一方面是对static成员变量的理解不到位,另一方面是分析的时候没有抓住有效信息浪费了不少时间。(“undefined reference to”)

4.C++静态成员变量

C++的变量的类型大致有普通成员变量、静态成员变量、成员常量这三种,还有一种组合的静态成员常量。

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

static成员的所有者是类本身和对象,但是多个对象拥有一样的静态成员。从而在定义对象时不能通过构造函数对其进行初始化; 静态成员不能在类定义里边初始化,只能在class body外初始化; 静态变量依旧符合public、private、protect特性; 静态成员函数没有this指针,它不能返回非静态成员,因为除了对象会调用它外,类本身也可以调用 。

C++静态成员变量:

  1. 必须在外部定义和赋值;
    • 不能在 main() 函数中定义
    • 不能在类的构造函数中定义
  2. 必须要定义静态变量,否则该变量没有内存空间(类中只是申明) ;
  3. 类本身可以直接调用静态变量
  4. 静态变量依旧符合public、private、protect特性

C++成员变量声明、初始化、赋值说明列表:

数据成员类型 normal const static static const
类内直接初始化(在声明时就赋值) ×
先声明再通过初始化列表赋初值 × ×
先声明再在构造函数体里赋初值 × × ×
先声明再在类外赋初值 × ×

5.C++静态成员方法

1、静态方法可以被类直接调用,但是同静态变量一样符合public、private、protect特性

2、静态成员函数不可以调用类的非静态成员。因为静态成员函数不含this指针。

3、静态成员函数不可以同时声明为 virtual或后缀const 函数。因为virtual就是用来区分是哪个对象调用了他,与静态方法矛盾。而后缀const是用来修饰this指针的,静态变量中不包含this指针。

参考资料:
https://blog.csdn.net/nwd0729/article/details/47067549
https://blog.csdn.net/buknow/article/details/80275191

猜你喜欢

转载自blog.csdn.net/mayue_web/article/details/88293640