在 c++ 中从世界调用私有方法
Call private method from the world in c++
我真的不明白为什么它有效,但下面的代码显示了在没有任何友元类的情况下从世界上调用私有方法的示例:
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 的方法。
说明符(public
、protected
和private
)不适用于成员函数或数据成员。它们适用于成员函数和数据成员名称。这行得通。如果可以引用没有名称的成员,则可以访问它。
这正是这里正在发生的事情。你正在调用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();
}
};
您的语义意味着此代码无法编译。
- 使用用户定义的参数调用future/async并调用类方法
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 将方法转换为调用该方法的成员函子对象会导致崩溃
- 是否可以依赖函数范围的静态变量来执行程序关闭期间调用的方法?
- 如何重写全局方法名称以在调用原始方法之前将我的代码推到前面
- 如何在 c++ 的类中递归调用函数方法?
- C++继承 - 为什么调用父方法?
- 是否可以从C++程序中调用 ACPI 方法?
- 如何在 c++ 中异步调用静态方法?
- 如何获取列表的每个对象并调用getName方法来打印其名称
- 从另一个标头中的标头调用静态方法
- 有没有办法从同一类中的函子调用类方法?
- 我的类中有方法的指针数组,但我不能调用我的方法.代码如下
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?
- 模拟系统调用——有更好的方法吗
- 在调用main函数之前,是否有方法解析命令行选项?
- 如何从没有共享超类的类调用公共方法
- 是否有另一种方法调用基方法从派生是虚拟的
- 从没有虚拟或引用的基方法调用子方法
- 是否有方法在调用函数时防止隐式的static_cast ?