色谱工作站(2)

时间:2022-02-16 19:19:43

对上篇中提到的问题,还有一种解决办法。

在C#中,除了public、protected和private访问修饰符之外,还有一种,叫internal,并且还能和protected组合成protected internal。

声明的可访问性

含义

public

访问不受限制。

protected

访问仅限于包含类或从包含类派生的类型。

internal

访问仅限于当前程序集。

protected internal

访问仅限于从包含类派生的当前程序集或类型。

private

访问仅限于包含类型。

internal很有意思。假设某个变量或者类型(称之为x吧)被internal修饰,那么,只有和x同属一个程序集的代码才能访问x。下面是来自MSDN的示例:

该示例包含两个文件:Assembly1.csAssembly2.cs。第一个文件包含内部基类BaseClass。在第二个文件中,实例化 BaseClass 的尝试将产生错误。

// Assembly1.cs
// Compile with: /target:library
internal class BaseClass
{
public static int intM = 0;
}
// Assembly2.cs// Compile with: /reference:Assembly1.dllclass TestAccess {   static void Main()    {      BaseClass myBase = new BaseClass();   // CS0122   }}

internal就是我们所需要的东西:

internal class CHasAAnalysisSystem { ... };

class CAnalysisSample : public CHasAAnalysisSystem
{
protected:
CAnalysisSample(CAnalysisSystem* pSystem):CHasAAnalysisSystem(pSystem){}
};

可惜C++中没有internal(托管C++有没有我不知道,没接触过),以后会不会有不敢保证,至少目前还没有。

值得庆幸的是,我们可以模拟它,虽然在一定程度上有点问题。

C++中有嵌套类(顺便提一下,还有局部类和匿名类。局部类如:

if(...) { 
class className{}; // 处于块中
className o;
}

局部类没有linkage属性,且不能作为模板参数。

匿名类如:

class { 
class {} m_o; //和嵌套类类似,但没有名字,不过可以直接生成实例;struct、union、enum的这种用法比较常见
};
)。

我们可以为嵌套类设置访问修饰符:

class OuterClass
{
public:// 或者protected、private
class InnerClass
{
};
};

那么,如何模拟C#中的internal呢?

其实很简单(针对我们的具体问题),我们只需要将CHasAAnalysisSystem设置为private即可。当然,为了能够访问CHasAAnalysisSystem,CAnalysisSample等也需要成为内部类。我们可以给外部类起名为Analysis,则CHasAAnalysisSystem和CAnalysisSample可以更名为CHasASystem和CSample。代码如下:

class Analysis
{
private:
class CHasASystem
{
};

public:
class CSample : public CHasASystem
{
protected:
CSample(CSystem* pSystem):CHasASystem(pSystem){}
};
};

如此,CSample中便无需写上一堆using,而又能达到我们的目的。

Analysis::CSample* pSample = ...;
Analysis::CHasASystem* pHasASystem = pSample; // 错误,无法访问Analysis::CHasASystem
delete pHasASystem; // 如果CSample和CHasASystem构成is-a关系,则应当可以通过基类的指针正确地删除派生类对象。
// 而事实上它们不是is-a关系,因此我们想在概念加以区分,在使用上加以禁止。

用内部类模拟internal来解决我们的问题,有两个小瑕疵:

首先,对于用户,必须使用完整的限定名:Analysis::CSample、Analysis::CMethod...如果是命名空间,则用户可以使用using Analysis;CSample、CMethod...

其次,用户阅读Analysis的代码时需要停顿:CHasASystem是private的,而CSample却public继承了它,说明CSample想继承CHasASystem的接口和实现,缺又不想暴露CHasASystem。

还有更好的办法吗?