You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

静态库中私有构造函数类可被主程序直接实例化的问题排查

问题:私有构造函数的类被主程序直接实例化

我开发了一个供其他应用调用的静态库,其中定义了构造函数为private的NumberHelpers类,本意是禁止主程序直接实例化该类,因此实现了静态方法作为单例对象的访问入口,还创建了Helpers辅助类统一提供库内各类实例的访问方式。但实际运行中出现异常:主程序仍能直接创建NumberHelpers的对象,尽管其构造函数是private的。

静态库代码

NumberHelpers.h

#pragma once
#include <memory>
using namespace std;

namespace helpme
{
    class NumberHelpers
    {
    private:
        NumberHelpers();
        static NumberHelpers* _Instance;

    public:
        static NumberHelpers& Instance()
        {
            if (_Instance == nullptr)
                _Instance = new NumberHelpers();
            return *_Instance;
        }

        double RoundTo(double no, int places);
    };
}

NumberHelpers.cpp

#include "pch.h"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <math.h>
#include "NumberHelpers.h"
using namespace helpme;

#pragma region static variables
NumberHelpers* NumberHelpers::_Instance = NULL;
#pragma endregion

NumberHelpers::NumberHelpers() 
{
}

double NumberHelpers::RoundTo(double no, int places)
{
    //Method - 1: By using setprecision
    std::stringstream strm;
    strm << std::fixed << std::setprecision(places) << no;
    return std::stod(strm.str());
}

Helpers.h

#pragma once
#include "NumberHelpers.h"
static class Helpers
{
public:
    static helpme::NumberHelpers& NumericHelper();
};

Helpers.cpp

#include "pch.h"
#include "Helpers.h"

helpme::NumberHelpers& Helpers::NumericHelper()
{
    return helpme::NumberHelpers::Instance();
}

主程序代码

HelperModules.h

#pragma once
#include <string>

namespace helpme
{
    extern class NumberHelpers
    {
    public:
        double RoundTo(double no, int places);
    };
}

static class Helpers
{
public:
    static helpme::NumberHelpers& NumericHelper();
};

MfcTestAppDlg.cpp

void CMfcTestingAppDlg::OnTestClick()
{
    //I want to access NumberHelpers like this
    double rndn = Helpers::NumericHelper().RoundTo(5.2483435643232, 2);

    //But I am also able to create object of NumberHelpers here whose constructor in private
    helpme::NumberHelpers nh;
    double testval = nh.RoundTo(4.2343, 2);
}

问题原因

  • 主程序的HelperModules.h中重新声明了helpme::NumberHelpers类,这个声明里没有定义private构造函数,编译器会默认生成一个public的默认构造函数,因此允许主程序实例化该类。
  • C++中,同一类的多次声明必须完全一致,否则会触发未定义行为,这里主程序的类声明与静态库中的类定义不匹配,绕过了私有构造函数的限制。

解决方案

1. 统一头文件依赖

删除主程序中HelperModules.h内的helpme::NumberHelpers和Helpers类声明,直接引用静态库提供的头文件:

#pragma once
// 直接引入静态库的辅助类头文件
#include "Helpers.h"

2. 修正主程序调用代码

修改MfcTestAppDlg.cpp,确保只通过合法方式访问单例:

#include "HelperModules.h"

void CMfcTestingAppDlg::OnTestClick()
{
    // 合法的单例访问方式
    double rndn = Helpers::NumericHelper().RoundTo(5.2483435643232, 2);

    // 此时以下代码会编译报错,私有构造函数限制生效
    // helpme::NumberHelpers nh;
    // double testval = nh.RoundTo(4.2343, 2);
}

3. 优化单例实现(可选)

当前单例实现非线程安全,建议改用C++11及以上支持的静态局部变量方式,实现简洁且线程安全的单例:

// 修改NumberHelpers.h中的Instance方法
static NumberHelpers& Instance()
{
    static NumberHelpers instance;
    return instance;
}

同时删除静态成员变量_Instance的定义,简化代码。

内容的提问来源于stack exchange,提问作者dipatel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 23:07:05