【问题标题】:Access private members of a class instantiated using interface访问使用接口实例化的类的私有成员
【发布时间】:2017-07-05 22:14:45
【问题描述】:

我有一个从接口派生的类和派生类的朋友类。我想访问被实例化为接口的派生类的成员。它看起来像这样:

界面:

class AInterface
{
public:
   virtual ~AInterface() = default;
   virtual void set(int a) = 0;
};

派生类 A 和朋友类 B:

class B;
class A : public AInterface
{
public:
   ~A() override {}
   void set(int a) override
   {
      mem = a;
   }
private:
   friend class B;

   int mem = 0;
};

B 类:

class B
{
public:
   B() 
   {
     a = new A();
     a->set(3);
   }

   int get_a()
   {
      // Access mem since it's a friend class
      return a->mem;
   }

private:
    AInterface *a;
}

主要:

int main()
{
    B *b = new B();
    std::cout << b->get_a() << std::endl;
    return 0;
}

程序无法编译,说 AInterface 没有名为“mem”的成员。 我是否需要接口中的getter函数并在A中实现它来实现这一点,还是有其他方法可以做到这一点?

【问题讨论】:

  • 提示:如果你做到public,它会起作用吗?
  • @juanchopanza 它会起作用,但我想保密并遵循原则。
  • 你试过了吗?
  • @juanchopanza 现在尝试了。不工作
  • 是的,接口中需要getter函数,并在A中实现,函数必须是虚函数。

标签: c++ class interface friend


【解决方案1】:

现在工作

#include <iostream>
using namespace std;


class AInterface
{
public:
    virtual ~AInterface() = default;
    int getMem() { return mem; }
    virtual void set(int a) = 0;
protected:
    int mem = 0;
};

class A : public AInterface
{
public:
    ~A() override {}
    void set(int a) override
    {
        mem = a;
    }


};

class B
{
public:
    B()
    {
         a = new A{};
        a->set(3);
    }

    int get_a()
    {
        // Access mem since it's a friend class
        return a->getMem();
    }

private:
    AInterface *a;
};
int main()
{
    B *b = new B();
    std::cout << b->get_a() << std::endl;
    return 0;
}
  1. 被孩子覆盖的纯方法应该是虚拟的。
  2. 如果每个类(子)Interface,变量int mem应该在接口中被保护。 现在可以正常工作了,如您所愿。
  3. 添加吸气剂getMem()

friend 的版本

#include <iostream>
using namespace std;


class AInterface
{
public:
    virtual ~AInterface() = default;
    virtual void set(int a) = 0;
protected:
    friend class B;
    int mem = 0;
};

class A : public AInterface
{
public:
    ~A() override {}
    void set(int a) override
    {
        mem = a;
    }


};

class B
{
public:
    B()
    {
         a = new A{};
        a->set(3);
    }

    int get_a()
    {
        // Access mem since it's a friend class
        return a->mem;
    }

private:
    AInterface *a;
};
int main()
{
    B *b = new B();
    std::cout << b->get_a() << std::endl;
    return 0;
}

【讨论】:

  • 为什么在这里使用friend 不正确?通过使用friend,OP 保留了封装,同时仅将其内部暴露给极少数人。通过添加 accessor 成员函数,现在可以将其暴露给整个世界。
  • @CaptainObvlious 好的,你说得对,每个开发者总是说“你从不使用`friend”,但我从来没有想过像特殊的接入点一样
【解决方案2】:

在你的 B 班。

class B
{
  //...
   int get_a()
   {
      return a->mem;   // but a is a AInterface*  !!!
   }

private:
    AInterface *a;     // That's not an A*, but an AInterface*
};

您有 2 个选项。

  1. 使用dynamic_cast&lt;&gt;

     int B::get_a()
     {
         A* p = dynamic_cast<A*>(a);
         if (p)
           return p->mem;  
         // a is not an A*, it's another AInterface*-type object !!!  
                                       // What should you do?
         throw something_or_other();   // throw?
         return -1;                    // return an error code?
       }
       // or maybe add..  so you can check for errors before calling get_a()
       A* B::get_A_ptr() const 
       { 
          return dynamic_cast<A*>(a); 
       }
    

dynamic_cast 工作正常,但如果您需要频繁读取 a-&gt;mem,可能会减慢您的应用程序。

  1. a 存储在A* 中,这可能是您从一开始就打算这样做...

    class B
    {
      // ...
    private:
      A* a;    // now a->A::mem is visible.
    };
    

由于您在 B 的构造函数中明确调用 new A,我认为选项 2 更适合您的情况。

【讨论】:

    猜你喜欢
    • 2014-05-18
    • 2010-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-03
    • 1970-01-01
    • 2020-09-25
    • 2012-12-17
    相关资源
    最近更新 更多