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

C++静态成员变量初始化和赋值1 背景有这样一套会话机制 CSession 为会话对象 CSessionMana 为会话管理类 在 CSession 会话需要销毁时 CSession 主动发送消息给 CSessionMana 销毁 session 同时 CSession 是一个基类 子类通过继承 CSession 实现不同的 session 处理 实现主要考虑三个方面 创建 处理 销毁 通过不同的 server 创建不同的 session

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/
https://blog.csdn.net/buknow/article/details/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232884.html原文链接:https://javaforall.net

(0)
上一篇 2025年9月3日 下午12:01
下一篇 2025年9月3日 下午12:22


相关推荐

  • 数据库置疑的解决方法_列族数据库

    数据库置疑的解决方法_列族数据库数据库置疑处理文档修订记录日期Date修订版本RevisionVersion修改描述ChangeDescription作者Author2010-04-261.0格式化UltraSQL目录一、知识点简介1.DBCC中的CHECKDB命令2.重置置疑状态3.sp_add_log_file_reco…

    2022年8月20日
    8
  • python flask教程_python框架有哪些

    python flask教程_python框架有哪些大家好,这算是我使用CSDN以来第一次正二八经的想自己写一篇博客。如果有写的不好的地方还请大家见谅!使用pipenv的方便之处就是可以单独的为每一个python 项目建立对应的虚拟环境,而且该过程简单方便。下面我会用简短的步骤来描述这个过程:1. 首先使用pip进行安装pipenv。 用管理员身份打开命令行(cmd),然后输入pipinstallpipenv 回车,结果如下图所…

    2022年8月28日
    10
  • jQuery下载和安装详细教程[通俗易懂]

    jQuery下载和安装详细教程[通俗易懂]下载jQuery我们可以到jQuery的官网下载jQuery文件(PS:其实jQuery就是一个封装了很多函数的js文件,把这个js文件导入到网页中就可以了)。jQuery官网地址:https://jquery.com/打开官网,即可看到jQuery的下载按钮,点击进入下载页面。有两个版本的jQuery可以下载:Productionversion-用于实际的网站中,是已经被精简和…

    2022年5月3日
    450
  • 超级邮件群发代理服务器设置,超级邮件群发教程

    超级邮件群发代理服务器设置,超级邮件群发教程本软件适合用于各种需要发送邮件到大量地址的应用 如电子报刊发行 邮件列表订阅发送 多客户企业联系 论坛版主 网站管理员等领域 是唯一一款按照国际标准 MIME 协议标准封装邮件的群发软件 而且功能之多 功能之强大 没有任何一款群发软件可比 发送邮件兼有 正常模式 和 特快专递 无须 SMTP 服务器 两种发送模式 并可自动切换 支持 SSL TLS 协议 可以使用 GMAIL 等要求安全连接的邮箱 提供线程数选

    2026年3月26日
    2
  • Sqlmap命令使用

    Sqlmap命令使用Sqlmap 基本命令使用 总结常用 23 条命令

    2026年3月18日
    3
  • OSPF报文类型

    OSPF报文类型OSPF 报文头格式 OSPF 用 IP 报文直接封装协议报文 协议号为 89 OSPF 分为 5 种报文 Hello 报文 DD 报文 LSR 报文 LSU 报文和 LSAck 报文 OSPF 这五种报文具有相同的报文头格式 长度为 24 字节 报文格式 字段解释 Version1 字节版本 OSPF 的版本号 对于 OSPFv2 来说 其值为 2 字段长度含义

    2025年11月30日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号