C++中的java“package private”等价物是什么?

jchrr9hc  于 2022-12-15  发布在  Java
关注(0)|答案(5)|浏览(167)

C中的java“package private”等价物是什么?Java包隐私特性(只有同一包中的类才具有可见性)在提供API时非常有用。
C
是否有类似的特性(除了声明其他类为“友元“)?详细说明,例如,假设A. h和B. h在同一个包(即API库)文件中:A.h

class A
{
public :
void doA();

private : 
 int m_valueA;
};

文件:B.h

class B
{
public : 
void doB()

private:
int m_valueB;

}

我想要的是,
公众可见度:仅限A::doA()和B::doB()
包内(即API库):A应该能够访问B::m_valueB,而B应该能够访问A::m_valueA。而无需使彼此成为“朋友”类。

zengzsys

zengzsys1#

C没有与Java概念“包”等价的东西。Java中的包是代码的任意集合,只通过收集在一起成为一个包来定义。
因此,“package private”有点像是对封装概念的嘲弄。是的,访问的范围在某种程度上是“有限的”,但它在很大程度上仍然是无限的。因此,这可能不是语言的一个自然特征。
虽然C
没有提供“包”的概念,但有一些方法允许特定的任意代码包调用其他任意代码包不能调用的函数。这需要使用“键类型”习惯用法。
“键类型”是一种(通常为空)类型,其主要特征是只有某些代码可以创建该类型的对象。因此,任何以这种类型作为参数的函数只能由能够创建该键类型的代码调用。因此,该类型“解锁”该函数;因此得名。
传统的用法是允许通过emplace和C++中类似的完美转发构造来转发私有访问。密钥类型的默认构造函数是private,只有显式的friend才能创建它。但是由于该类型是可公开复制的,任何转发函数都可以将它们复制到目的地。
在您的例子中,您希望键类型只能从某些 * 文件 * 中的代码构造。要做到这一点,您只需有一个提供键类型定义的头文件,通常是一个简单的空类。在您的“包”的公共头文件中,任何您希望成为“包私有”的函数都将接受package_private作为const&参数。
但是,您的“package”的公共头文件不包括package_privatedefinition;这意味着那些只能访问公共头文件的代码不能创建该类型的对象。它们可以看到类型名,但不能对它做任何事情。
它可能看起来像这样:

//Internal header, included by all code in the "package"
struct package_private {};
inline constexpr static package_private priv; //Makes it easier to call these functions

//Header for library.
struct package_private;
void package_private_function(package_private const&, ...); //Must be `const&` to avoid needing to define `package_private`.

//To call the package private function inside the library:
package_private_function(priv, ...);

//This is a compile error for any code that doesn't have the internal header:
library::package_private priv{};
library::package_private_function(priv, ...);

C就是C,用户总是可以 * 作弊 *:

alignas(max_align_t) char data[sizeof(max_align_t)];
library::package_private &key = *reinterpret_cast<library::package_private*>(&data);

instance.pack_priv_function(key, ...);

这在C20中甚至不是未定义的行为,只要package_privatedata的给定对齐和大小范围内,并且它是隐式生存期类型,你可以做一些事情来强制package_private不是这些东西,但这只会使代码UB。它仍然可以编译,几乎可以肯定仍然 * 工作 *;毕竟,这个函数从来没有访问过这个对象。
提示用户头中的某些类型是内部的,不应该被外部代码使用的传统方法是将其粘贴到detail命名空间中。
C
20模块提供了一种方法来防止破坏这一点。如果我们认为一个模块是一个“包”,你所要做的不是exportpackage_private类型。它仍然可以被列为参数的函数得到导出(他们不再需要const&)。但package_private类型本身并没有导出。
模块内的代码可以使用该名称;你可以把定义放到一个实现分区中,这个分区可以被任何需要这个访问的模块内文件所访问。但是在import所在的模块之外的代码不能使用这个名字,所以他们甚至不能使用上面所示的强制转换技巧。有一些元编程技术可以在不知道函数类型的情况下检查它的签名。但这些都很难,而且会被超载破坏。
不过,Java反射可以破坏任何封装,因此“package private”并不是万无一失的。

ldfqzlk8

ldfqzlk82#

c++没有java中的包,但是它有命名空间,然而命名空间只是一个namespace,所以它是一个不同的野兽。
在某些情况下,某种程度上的模拟可能是内部类(其他类中的类)-因为内部类被认为是成员。
除此之外,有头文件和实现(.cpp文件)-从这个意义上说,你有单元或模块控制什么是实际可见的(不仅是私有的,而且是完全隐藏的-- * 特别是在放入anon.namespace * 中时)。这个概念既包括单个.h文件和.cpp文件,也包括整个projects/libs/dll,后者更像是一个完整的包(并且可以选择通过在各自的头文件中“显示”什么来公开API的哪些部分)。

gj3fmq9x

gj3fmq9x3#

你可能会对C++中的PIMPL习惯用法感兴趣,正如@darune所说,它不是等价的,但在语义上很接近。
位于您的公共类.hpp

class MyPublicClass
{
    // Public interface
public:
   void doSomething();
   
   void manipulatePrivateStuff(Stuff * stuff);

   MyPublicClass(...);
   ~MyPublicClass();

   struct Stuff;  // <= This is were the magic happens, this stuff 
                  //    is unknown/private from who include this header

private: 
   Stuff * _member;
};

您的公共类.cpp

#include <iostream>
#include "YourPublicClass.hpp"

struct MyPublicClass::Stuff
{
    // Public members that are only accessible from this compilation unit
    // but private from the rest of the code, like a private package

    int a;
    
    void explodeInTenSeconds() { if (!a--) std::cout<<"Boom!"<<std::endl; }

    Stuff(int delay = 10) : a(delay) {}
};

void MyPublicClass::doSomething() { _member->explodeInTenSeconds(); }
void MyPublicClass::manipulatePrivateStuff(Stuff * stuff) { stuff->a = 10; }

MyPublicClass::MyPublicClass(...) : _member(new Stuff(10)) {}
MyPublicClass::~MyPublicClass() { delete(_member); }

如果您需要另一个类来访问“packageprivate”Stuff,您需要将MyPublicClass::Stuff声明移到它自己的头文件中,并将该头文件包含在该类的定义文件中(.cpp).这个头文件不应该包含在你的“包”之外,它不是公共的.它不需要被操纵,编译器完全可以只知道它是一个指向未指定结构的指针。

n3h0vuf2

n3h0vuf24#

C没有软件包。
结果是所请求的行为“对我的包内的其他代码的访问不同于对我的包外的代码的访问”甚至没有意义。没有“我的包内的代码”,因为没有“我的包”。
更进一步地说,C
private访问修饰符符合Java package private的规范。对于包之外的代码,它是不可访问的(private),就像Java package private一样。对于同一个包之内的代码,它是可以轻松访问的---因为没有这样的代码。
显然,这对建立合作关系没有任何帮助。但是,当你试图问一些关于C的问题时,你会得到一些只有在其他语言中才有意义的问题。你的问题的另一个方面是以Java为中心的,对思考C有害,那就是你认为所有的代码都可以组织成类。在C++中,情况并非如此。存在不是类成员的自由函数和关联(通过ADL)函数。

yftpprvb

yftpprvb5#

首先,理解private-package是很重要的。它意味着同一个包中的其他成员可以访问该项目。java中的包是一个任意的代码集合,它只通过在bundle中收集来定义。C++中“private-package”的这一特性与java语言是不等价的。

相关问题