C++ 库制作,在 header 中没有朋友的情况下隐藏 destructor/constructor
C++ library making, hiding destructor/constructor without friend in header
我必须创建一个共享库,现在我面临以下问题。 (MSVC2015)。我想像 class A 那样隐藏 constructor/destructor,而我有一个像 B 那样的 "factory" class。
class A {
public:
private:
A() {};
~A() {};
friend class B;
};
class B {
public:
B() {};
~B() {};
A * Create() { return new A(); };
};
所以我编译这两个 classes 来创建一个 .lib 和一个 .dll。我的问题是,如果我给用户 header 文件,其中包含 class A 的定义加上 .lib 和 .dll,但从这个 [=26= 中删除 friend class B 行] 那么它会是一个有效的解决方案吗?换句话说: "friend class" 是仅在编译时需要还是在运行时也需要?
感谢您的帮助!
如果你用朋友线编译它然后删除朋友线,你的用户总是可以再次添加它。您的用户也可以将函数从私有更改为 public.
如果 A::A()
的实现由您的库导出是一个不同的问题,并且在 windows 下由 declspec(dllexport/import)
属性确定,因此独立于 private/public 它可能是否对用户可用。据我目前所见,public,私有和友元声明对编译的 dll 没有影响,使用 member-pointers 你甚至可以在不编译 dll 的情况下访问私有成员。但是在这一点上不能保证。
真正的问题是:你为什么要这样做?
如果您在 header 中声明此构造函数是私有的并且只能由 B
访问,请在 B
中提供一个工厂函数并(希望)在您的文档中声明用户应该使用此工厂, 那么你已经做了一切合理的事情来阻止用户使用这个 class。如果他还是这样,那就不是你的错了。
编辑:(接受挑战)
我刚刚用 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
所以我们学到的是:这里的构造函数是在 class 定义中定义的,所以即使没有 _declspec(dllexport/import) 可执行文件也可以访问它。我们实际上 可以 将 private 更改为 public 并可以访问构造函数。 member-function print()
.
也是如此
即使我不仅省略了可执行文件 header 中 bar()
的 fried 声明,而且省略了 bar()
使用的完整函数定义,但它不是bar 打印字符串的问题 - 仅仅是因为 bar()
的代码已经编译在 .dll.
中
很明显,class 完全由其 member-variables 及其布局定义,函数和访问说明符都不需要相同。 但是我没有声明这符合标准,保证有效或应该完成
我必须创建一个共享库,现在我面临以下问题。 (MSVC2015)。我想像 class A 那样隐藏 constructor/destructor,而我有一个像 B 那样的 "factory" class。
class A {
public:
private:
A() {};
~A() {};
friend class B;
};
class B {
public:
B() {};
~B() {};
A * Create() { return new A(); };
};
所以我编译这两个 classes 来创建一个 .lib 和一个 .dll。我的问题是,如果我给用户 header 文件,其中包含 class A 的定义加上 .lib 和 .dll,但从这个 [=26= 中删除 friend class B 行] 那么它会是一个有效的解决方案吗?换句话说: "friend class" 是仅在编译时需要还是在运行时也需要?
感谢您的帮助!
如果你用朋友线编译它然后删除朋友线,你的用户总是可以再次添加它。您的用户也可以将函数从私有更改为 public.
如果 A::A()
的实现由您的库导出是一个不同的问题,并且在 windows 下由 declspec(dllexport/import)
属性确定,因此独立于 private/public 它可能是否对用户可用。据我目前所见,public,私有和友元声明对编译的 dll 没有影响,使用 member-pointers 你甚至可以在不编译 dll 的情况下访问私有成员。但是在这一点上不能保证。
真正的问题是:你为什么要这样做?
如果您在 header 中声明此构造函数是私有的并且只能由 B
访问,请在 B
中提供一个工厂函数并(希望)在您的文档中声明用户应该使用此工厂, 那么你已经做了一切合理的事情来阻止用户使用这个 class。如果他还是这样,那就不是你的错了。
编辑:(接受挑战)
我刚刚用 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
所以我们学到的是:这里的构造函数是在 class 定义中定义的,所以即使没有 _declspec(dllexport/import) 可执行文件也可以访问它。我们实际上 可以 将 private 更改为 public 并可以访问构造函数。 member-function print()
.
也是如此
即使我不仅省略了可执行文件 header 中 bar()
的 fried 声明,而且省略了 bar()
使用的完整函数定义,但它不是bar 打印字符串的问题 - 仅仅是因为 bar()
的代码已经编译在 .dll.
很明显,class 完全由其 member-variables 及其布局定义,函数和访问说明符都不需要相同。 但是我没有声明这符合标准,保证有效或应该完成