【问题标题】:How can we access to the private virtual method in C++?我们如何访问 C++ 中的私有虚拟方法?
【发布时间】:2015-11-03 17:37:55
【问题描述】:

我有一个类包含一个私有属性和一个虚拟方法。

class A
{
  private:
    int var1;
    virtual int foo()
     { return var1;}
 public:
    A(){  var1 = 2; }
};

在我的“主要”功能中,我有:

 A a;
 cout<<func1(&a);

我想在不改变类的情况下在“func1”中获取 var1 的值和“foo”函数的返回值。 如果我想解决它,我可以为 var1 添加 set 和 get 方法,但我不打算更改类。 这怎么可能?从类外部访问私有方法和属性的任何参考?

【问题讨论】:

  • 不破坏 C++ 语言规则是不可能的。这正是private 的用途:您不能从外部访问成员。见gotw.ca/gotw/076.htm
  • @AnonMail:我希望没有“教授”参与这个毫无意义的练习。
  • @EdHeal 它可以很好地与 NVI 成语 gotw.ca/publications/mill18.htm 一起使用。
  • @EdHeal:那是错误的。私有虚成员函数是 C++ 中的最佳实践
  • 这里有一个非常相似的问题:Accessing private members

标签: c++ object private-members


【解决方案1】:

你不能从类外部访问私有方法。

但是,该方法是虚拟的,它可以被派生类覆盖,即使它是私有的。当调用虚方法时,会调用被覆盖的版本。

【讨论】:

  • 这将如何允许访问A::varA::foo()
  • @R Sahu,它不允许访问 A::var 或 A::foo()。但它确实允许您在课堂上重新实现它。 @R Sahu 建议使用friend,但这需要修改基类,在这种情况下您可以将private 更改为protected
  • @JaredDykstra:所以,总而言之,你对提出的问题没有答案?
  • @JaredDykstra 能够重新实现foo 有什么意义,任务是获取 var1 的值和“foo”函数的返回值,两者子类无法访问?
  • 连同在基类中实现的一些(公共)模板函数,允许这个函数被覆盖是很有意义的。我记得有这个特定的用例here
【解决方案2】:

访问类的private 方法和变量的唯一方法是通过friend 声明——将类或函数设为friend

如果不允许以任何方式修改类,则无法从func1 访问private 方法或变量。

【讨论】:

  • @R Sahu 是的,你是对的,我知道,但关键是我想找到一种访问这些隐私的方法!
  • @Rubbic 事实上你不能。关键是,您可以在派生类中重新实现它们。这是这个类允许改变行为的唯一可行方式。
  • @Rubbic,您也许可以找到一种非标准的方式来操作指针并访问成员变量。我不知道有一种符合标准的方式来完成你正在尝试的事情。
【解决方案3】:

如前所述,您只能从同一类中或通过类的友元函数访问类的私有成员

由于func 既不是A 类的成员,也不是A 类的友元函数,那么您不能从func 调用私有函数foo...除非我们进行一些更改。

观察到您将A 对象的地址传递给func,并且您希望调用私有函数foo,然后将func 实现为A 类的友元函数应该是明显的选择。

#include<iostream>

class A
{
    public:
        A():var(2){}
        virtual ~A(){}
        friend int func(A const* a){return a->foo();}
    private:
        virtual int foo() const{return this->var;}
        int var;
};

int main()
{
    A a;

    std::cout << func(&a) << std::endl;

    return 0;
}

【讨论】:

  • 我喜欢你的解释。正如其他答案中提到的,无法在“func”中调用这些私有方法,您的建议是更改 A 类本身。我喜欢你的措辞。
  • @Rubbic,很高兴我能帮上忙。
【解决方案4】:

在 C++ 意识形态中,您无法读取或修改其他类中的私有成员 - 它被命名为“封装”。

但是,这个 hack 代码可以在所有流行的编译器上成功运行:

int& func1(A* a)
{
    struct Hacker  // copy of class A in memory by structure
    {
        int var1;
        virtual void fakeUnused() { }  // need because A have one virtual function too
    };
    Hacker* hacker = reinterpret_cast<Hacker*>(a);
    return hacker->var1;
}

现在,您可以读写 A::var1:

A a;
cout << func1(&a) << endl;  // prints '2'

func1(&a) = 3;
cout << func1(&a) << endl;  // prints '3'

但是,不要在真正的代码中使用这个技巧!这是非常糟糕的做法!由于此代码不完全可移植。

【讨论】:

  • 我认为用故意违反语言的内容回答问题没有用处。
  • 哇!这确实有效!!!!但我认为这是违规行为!基于所有的讨论,很明显没有正确的方法解决这个问题,唯一的方法就是这个!
  • @legalize 是的,这违反了 C++ 规则。我回答说。但是,它曾经是主题启动器的真正解决方案。在非企业中,对于当前的 C++ 知识,在 scholl 中此解决方案将很有用。
  • @Rubbic 此解决方案成功地与 x86 和 x86-64 架构上的 llvm、gcc、msvc 编译器配合使用。但是,如果您在便携式解决方案中搜索企业代码,请不要使用它。是的,这种方法曾经是真正的解决方案:)
  • 虽然通过使用不安全的技术故意颠覆语言可能会“起作用”,因为它不会崩溃,但这不是我们应该推荐的堆栈溢出的那种“技巧”作为真实的答案。这是人们通过 google 找到的东西,然后添加到实际系统中并导致比他们解决的问题更多的问题。
猜你喜欢
  • 2012-11-30
  • 1970-01-01
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
  • 2017-10-16
  • 2011-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多