在 c++ 中从世界调用私有方法

Call private method from the world in c++

本文关键字:调用 有方法 世界 c++      更新时间:2023-10-16

我真的不明白为什么它有效,但下面的代码显示了在没有任何友元类的情况下从世界上调用私有方法的示例:

class A
{
public:
    virtual void someMethod(){
        std::cout << "A::someMethod";
    }
};
class B : public A
{
private:
    virtual void someMethod(){
        std::cout << "B::someMethod";
    }
};
int main(){
    A* a = new B;
    a->someMethod();
}

输出:

B::someMethod

它不违反C++的封装规则吗?对我来说,这太疯狂了。继承是公共的,但派生类中的访问修饰符更改为私有,因此类 B 中的someMethod()是私有的。所以其实做a->someMethod(),我们直接从天下调用一种私有方法。

考虑以下代码,这是对原始问题中代码的修改:

class A
{
public:
    virtual void X(){
        std::cout << "A::someMethod";
    }
};
class B : public A
{
private:
    virtual void Y(){
        std::cout << "B::someMethod";
    }
};
int main(){
    A* a = new B;
    a->X();
}
很容易

理解调用 X() 是合法的。B 作为公共成员从 A 继承它。从理论上讲,如果 X() 调用 Y(),这当然也是合法的,尽管这是不可能的,因为 X() 是在不知道 Y() 的 A 中声明的。但实际上,如果 X = Y,即如果两个方法具有相同的名称,则就是这种情况。

你可以把它想象成"B 从 A 继承了一个公共方法,该方法调用一个同名的私有方法(B 的)"。

>a是指向该方法为公共的A对象的指针,因此这不是违规行为。由于您已经使用了virtual,因此考虑了VTABLE,并且您得到的输出为B::someMethod。

对我来说,

这很简单。由于允许您将类的任何动态类型继承分配给 parrent 类的对象,因此反之亦然。但是,当您将 Child 分配给其 parrent 对象指针时,这可能会很糟糕,就好像 B 的类比 A 大一样。

如果程序尝试通过以下类型之一以外的左值访问对象的存储值,则行为是未定义的:

  • 对象的动态类型,
  • 对象的动态类型的 CV 合格版本,
  • 一种类型,该类型是对应于对象的动态类型的有符号或无符号类型,
  • 一种类型,
  • 该类型是与对象的动态类型的 CV 限定版本相对应的有符号或无符号类型,
  • 在其成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含的联合的成员),
  • 一种类型,该类型是对象的动态类型的基类类型(可能符合 CV 标准),
  • 字符或无符号字符类型。

因此,就像在您的代码中一样,您不符合此条件,但是由于 B 的大小为 A,因此可以运行它。但这是未定义的行为。当你创建一个new B a 指向的内存块具有打印 B 而不是 A 的方法。

访问控制

说明符(publicprotectedprivate)不适用于成员函数或数据成员。它们适用于成员函数和数据成员名称。这行得通。如果可以引用没有名称的成员,则可以访问它。

这正是这里正在发生的事情。你正在调用B::someMethod,但你使用名称 A::someMethod 来调用它,这是公共的。没关系。

您建议私有成员函数不应从类外部调用(暂时忽略朋友)。在以下情况下,所需的语义将如何工作?

共享库hider

hider.h

typedef void (*FuncType)();
class Hider {
private:
  static void privFunc();
public:
  static void pubFunc();
  FuncType getFunction() const;
};

hider.cpp

#include <cstdlib>
#include <iostream>
#include "hider.h"
void Hider::privFunc() {
  std::cout << "Privaten";
}
void Hider::pubFunc() {
  std::cout << "Publicn";
}
FuncType Hider::getFunction() const {
  if (std::rand() % 2) {
    return &pubFunc;
  } else {
    return &privFunc;
  }
}

使用库hider的应用程序

#include "hider.hpp"
int main()
{
  Hider h;
  FuncType f = h.getFunc();
  f();
}

打电话给f()呢?它应该在运行时 50% 的时间因某种形式的access control violation而失败吗?


正如 DyP 在评论中建议的那样,更现实的场景是众所周知的"模板方法"设计模式:

class Container
{
public:
  void insert(const Item &item) {
    preInsert();
    data.insert(item);
    postInsert();
  }
private:
  std::vector<Item> data;
  virtual void preInsert() = 0;
  virtual void postInsert() = 0;
};

class ThreadSafeContainer : public Container
{
private:
  std::mutex m;
  virtual void preInsert() {
    m.lock();
  }
  virtual void postInsert() {
    m.unlock();
  }
};

您的语义意味着此代码无法编译。