从基类继承私有成员

时间:2013-02-26 22:20:44

标签: c++ class templates inheritance private

这个问题已经被提出here - 实际上已经超过两次了 - 但是我自己也无法从帖子中找到解决问题的方法。

我拥有的是一个库,其中包含一个名为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 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:2)

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

  

并且我不确定更改可见性是否会导致其他任何事情崩溃。

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

答案 2 :(得分:1)

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

除此之外,如果不严重违反C ++的规则和惯例,就无法授予B A_mapA的访问权。

顺便说一句,私有继承意味着别的东西。这意味着类B的所有公共方法都将成为类A的私有方法。换句话说,私有继承意味着您继承了{{1}}的实现,而不是它的接口。所以这对你没用。

答案 3 :(得分: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;
    };