当前位置: 首页 > news >正文

C# vs C++之三:静态构造函数

在C#中,类的静态构造函数用于在使用类之前进行相关的初始化工作;比如,初始化静态成员或执行特定操作。CLR 在第一次创建该类对象调用该类静态方法时自动调用静态构造函数。同时,CLR保证静态构造函数的线程安全性(准确地说是,只会调用一次,不存在多线程问题)。

 

下面是MSDN对静态构造函数特点的描述:

1.静态构造函数既没有访问修饰符,也没有参数

2.在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类

3.无法直接调用静态构造函数

4.在程序中,用户无法控制何时执行静态构造函数

 

C++语言规范并未包含类似静态构造函数的东西,但在使用类之前做初始化工作的需求却是客观存在的。就满足需求本身来讲,C++完全可以通过手动方式实现,但要处理好初始化时机,线程安全性等问题。本文则尝试通过C++的模版机制模拟实现静态构造函数,避免手动初始化的繁琐实现。对于需要静态构造函数的类A,只需用继承static_constructable<A>模版类,并提供 static void statici_constructor()静态方法即可:

class A : static_constructable<A>
{
public:
    static void static_constructor() {
        std::cout << "static constructor a" << std::endl;
        s_string = "abc"; //初始化静态数据
    }

    static std::string s_string;

public:
    A(){
        std::cout << "constructor a" << std::endl;
    }

private:
    int m_i;
};

std::string A::s_string;

int _tmain(int argc, _TCHAR* argv[]){
    std::cout << "beginning of main" << std::endl;

    assert(sizeof(A) == sizeof(int));//继承不改变A的内存布局
    assert(A::s_string == "");
    A a1;
    assert(A::s_string == "abc");
    A a2;
    std::cout << "end of main" << std::endl;

    return 0;
}

输出:

beginning of main
static constructor a //创建A对象前自动调用静态构造方法,一次且仅一次
constructor a
constructor a
end of main

 

下面是static_constructable类模板的实现:

template<typename T>
class static_constructable
{
private:
    struct helper{
        helper(){
            T::static_constructor();
        }
    };

protected:
    static_constructable(){
        static helper placeholder;    
    }
}

上面的实现把对A::static_constructor()的回调放到内部类helper的构造函数中;并在static_constructable<A>()中定义一个helper局部静态变量;C++保证在构造派生类 A的对象时,会先调用基类static_constructable<A>的构造函数,且静态局部变量只会构造一次,这样就达到调用一次且仅一次A::static_constructor()的目的。< /span>

 

static_constructor类模板简单地模拟了C#的静态构造函数机制,它具有以下特点:

1. 在第一次构造类对象之前自动调用类提供的静态构造函数
2. 静态构造函数被调用的时机是确定的
3. 利用了C++的局部静态变量初始化机制保证了线程安全性 (更正:实际并非线程安全,C++标准不涉及多线程问题,而一般编译器实现也非线程安全,更多参见评论部分)
4. 基于继承的实现机制并未改变派生类的对象内存布局

 

不过,和本文开始列出的C#静态构造函数的几个特点相比,本实现还有明显的不足:无法通过调用类A的静态方法触发静态构造函数;类A的静态构造函数必须是public的。希望有更好解决方案的朋友不吝赐教,也欢迎对此话题感兴趣的朋友交流探讨!

相关文章:

  • Salesforce中所有常用类型字段的取值与赋值
  • 利用arcgis发布综合又详细的地理定位服务
  • SQL Server 6.5 如何升级到SQL Server 2000—以前原创(二)
  • 驱动注册的probe函数
  • Entity Framework中IQueryable, IEnumerable, IList的差别
  • oracle序列详解
  • Win C盘扩容
  • 下载网站-资源共享
  • 汇编逻辑运算指令
  • 应用系统之间数据传输的几种方式
  • 使用SCOM 2012监控网络
  • ASP.NET MVC在服务端把异步上传的图片裁剪成不同尺寸分别保存,并设置上传目录的尺寸限制...
  • 有关AngularJS请求Web API资源的思路
  • C# 调用 C++ Dll 类库的传参问题
  • 转:fastText原理及实践(达观数据王江)
  • 分享的文章《人生如棋》
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • C++类的相互关联
  • HTTP那些事
  • IndexedDB
  • JavaScript新鲜事·第5期
  • PHP变量
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 基于组件的设计工作流与界面抽象
  • ------- 计算机网络基础
  • 力扣(LeetCode)357
  • 聊聊directory traversal attack
  • 前端性能优化--懒加载和预加载
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 追踪解析 FutureTask 源码
  • 06-01 点餐小程序前台界面搭建
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • #100天计划# 2013年9月29日
  • (C)一些题4
  • (k8s中)docker netty OOM问题记录
  • (Oracle)SQL优化技巧(一):分页查询
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (SpringBoot)第七章:SpringBoot日志文件
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (定时器/计数器)中断系统(详解与使用)
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (原)本想说脏话,奈何已放下
  • (转)我也是一只IT小小鸟
  • (轉貼)《OOD启思录》:61条面向对象设计的经验原则 (OO)
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .NET CORE 第一节 创建基本的 asp.net core
  • .NET Framework与.NET Framework SDK有什么不同?
  • .Net FrameWork总结
  • .net 发送邮件
  • .net 使用ajax控件后如何调用前端脚本