C ++库制作,在标题中隐藏没有朋友的析构函数/构造函数

时间:2016-03-02 21:37:10

标签: c++ constructor destructor friend

我必须创建一个共享库,现在我面临以下问题。 (MSVC2015)。我想隐藏类A中的构造函数/析构函数,我有一个"工厂"像B这样的班级。

class A {
     public:
     private:
         A() {};
         ~A() {};
     friend class B;
};

class B {
   public:
   B() {};
   ~B() {};
    A * Create() { return new A(); };
};

所以我编译这两个类来创建.lib和.dll。我的问题是,如果我向用户提供包含A类定义加上.lib和.dll的头文件,但是从该头中删除了行友B类,那么它是否是一个有效的解决方案?换句话说:是"朋友班"是仅在编译时需要还是在运行时也需要它?

感谢您的帮助!

1 个答案:

答案 0 :(得分:-1)

如果您使用好友行编译它然后删除好友行,您的用户可以再次添加它。您的用户也可以将功能从私人更改为公共。

如果您的库导出A::A()的实现是一个不同的问题,并且在由declspec(dllexport/import)属性确定的窗口下,因此独立于私有/公共,它可能对用户可用。从我到目前为止看到的,公共,私有和朋友声明对编译的dll没有影响,并且使用成员指针甚至可以在不编译dll的情况下访问私有成员。但是在这一点上没有保证。

真正的问题是:你为什么要这样做?
如果你在标题中声明这个构造函数是私有的并且只能由B访问,那么在B中提供一个工厂函数并且(希望)在你的文档中说明用户应该使用这个工厂,那么你有做了一切合理的事情,以防止用户使用这个类。如果他仍然这样做,那不再是你的错。

编辑(接受挑战)

我刚刚使用MSVC 2015编译了以下.dll:

//class.cpp
#include "class.h"

void bar(C & c)
{
    c.privatePrint();
}

//class.h
#pragma once
#include <string>
#include <iostream>

class C {
private:
    std::string str;
    C() :str("foo") {}

    void print() {
        std::cout << str << std::endl;
    }

    void privatePrint() {
        std::cout << "private " << str << std::endl;
    }

    friend _declspec(dllexport) void bar(C& c);
};

_declspec(dllexport) void bar(C& c);

并将其加载到以下.exe:

//main.cpp
#include <iostream>
#include "class.h"
#pragma comment(lib,"../Debug/lib.lib")

int main(){
    C c;

    bar(c);
    c.print();
}

//class.h
class C {
public:
    std::string str;
    C() :str("foo") {}

    void print() {
        std::cout << str << std::endl;
    }
};

_declspec(dllimport) void bar(C& c);

输出:

private foo
foo

所以我们学到的是:这里的构造函数是在类定义中定义的,所以即使没有_declspec(dllexport / import),可执行文件也可以访问它。实际上,我们可以将私有更改为公共,并且可以访问构造函数。成员函数print()也是如此 即使我不仅在可执行文件头中省略了bar()的frished声明,而且还省略了bar() 使用的完整函数定义,因此bar打印字符串没有问题 - 只是因为bar()的代码已经在.dll中编译。

显然,一个类完全由其成员变量及其布局定义,函数和访问说明符都不需要相同。 但是,我并未声明这符合标准,保证可以使用或应该完成