2

这个问题已经在这里被问过——实际上不止两次——但我自己无法从帖子中找到解决我的问题的方法。

我所拥有的是一个库,其中包含一个名为的类A。从课堂A上我需要访问一个std::map<>,但它是私有的。此外,根据我在我提到的帖子中发现的可能性,类没有A模板化功能。

我实际上能够重新编译库,这样我就可以简单地改变可见性。但是,这将是很多工作——而且我不确定改变可见性是否不会让其他任何东西崩溃。

我想做的是,在课堂上B

// NOT MY CODE -- library <a.h>
class A {
private:
    std::map<int, int> A_map;
};

// MY CODE -- module "b.h"
# include <a.h>
class B : private A {
public:
    B() {
        for (auto it(A_map.begin()); it != A_map.end(); ++it) {
            ...;
        }
    }
};

我如何在不更改原始类的情况下做到这一点——并且在基类中没有任何可用的模板化方法可以重载/专门化?

4

4 回答 4

3

您首先应该非常确信您尝试做的事情实际上是有效的……变量是私有的可能有充分的理由。修改它可能会破坏 A 实例的状态,并且不能保证私有变量在您破坏封装以读取它时将处于逻辑或一致状态。

有了这个警告,如果你可以修改/重新编译库,声明你的类是 A 的朋友可能是要走的路。让 B 通过组合持有 A 的实例,并且由于它是朋友,它可以访问 A 实例的私有成员。


而且,因为我感觉特别邪恶,这里有一个演示如何在不修改 A 的情况下打破封装。虽然它不是可移植的(我在 64 位 linux 上使用 g++ 工作)并且涉及弄清楚内存中的对象布局。为简单起见,我将地图更改为矢量。

#include<vector>
#include<iostream>

class A {
private:
    int blah; //Just to make it a bit more realistic.
    std::vector<int> A_vec;
public:
    void outputVec() {
       std::vector<int>::iterator it = A_vec.begin();
       while(it != A_vec.end()) {
         std::cout << *it << std::endl;
         ++it;
        }
    }
};


int main() {
  A* a = new A();
  std::vector<int>* v = (std::vector<int>*)(((char*)a)+sizeof(long));
  v->push_back(27);
  v->push_back(12);
  a->outputVec();
  return 0;
}
于 2013-02-26T22:42:51.180 回答
2

特意保护私有变量免受任何外部访问。如果拥有类允许通过较少限制的访问或结交朋友,您只能访问成员。

而且我不确定改变可见性是否不会让其他任何东西崩溃。

C++ 中的访问限制是有意设计的,因此可访问性是在进行名称查找时检查的最后一件事。这意味着如果您有一个工作程序并且您使某些东西更易于访问,那么该程序的行为根本不应该改变,因为在检查可访问性之前已经检查了所有其他潜在问题。

于 2013-02-26T22:38:48.027 回答
1

首先,将所有数据成员保密是一个非常好的主意。如果您的派生类确实需要访问A_map,那么最好的办法是给基类一个 getter,它返回一个对它的 const 引用(假设您只需要读取访问权限)。如果您需要对 的写入权限A_map,那么这很好地表明您需要重新考虑您的设计。

除此之外,如果不严重违反 C++ 的规则和约定,就无法授予类B访问权限。A_map

顺便说一句,私有继承意味着别的东西。这意味着 class 的所有公共方法都A将成为 class 的私有方法B。换句话说,私有继承意味着你继承了 的实现A,而不是它的接口。所以在这里它不会帮助你。

于 2013-02-26T22:35:55.400 回答
0

私有继承真的是变相的组合!它实际上的意思是“实施”。

撇开这一点不谈,无论私有/公有/受保护的继承模式如何,私有成员都将保持私有(在该类之外无法访问,即使是派生类也是如此)。

有两种合法的方式可以访问任何类的私有成员。

1) 使用 Get/Set 方法访问私有成员(假设类公开它)。

2) 与班级交朋友。

在您的情况下,A 类属于一个库,库供应商有责任为外部世界与 A 类交互提供适当的接口。也许,最好与库供应商交谈。对我来说,它看起来更像是一个设计问题而不是实现问题。

只是为了测试,作为一种快速破解,我建议使用好友机制。

    class A {
      friend class B;
      private:
      std::map<int, int> A_map;
    };

    // MY CODE -- module "b.h"
    class B {
     public:
     B() {
      for (std::map<int, int>::iterator  it(a.A_map.begin()); 
          it != a.A_map.end(); ++it) {  }
     }
     A a;
    };
于 2013-02-27T05:25:06.480 回答