- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
以下代码打印“I'm B!”。这有点奇怪,因为 B::foo()
是私有(private)的。关于A* ptr
,我们可以说它的静态类型是A
(foo
是public),它的动态类型是B
(foo
是私有(private)的)。所以我可以通过指向 A
的指针调用 foo
。但是这样我就可以访问 B
中的私有(private)函数。可以算作封装违规吗?
由于访问限定符不是类方法签名的一部分,因此会导致这种奇怪的情况。为什么在覆盖虚函数时不考虑 C++ 中的访问限定符?我可以禁止这种情况吗?这个决定背后的设计原则是什么?
#include <iostream>
class A
{
public:
virtual void foo()
{
std::cout << "I'm A!\n";
};
};
class B: public A
{
private:
void foo() override
{
std::cout << "I'm B!\n";
};
};
int main()
{
A* ptr;
B b;
ptr = &b;
ptr->foo();
}
最佳答案
你有很多问题,所以我会尽量一一回答。
因为在所有重载决议之后,编译器都会考虑访问限定符。这种行为由标准规定。
例如,参见 on cppreference :
Member access does not affect visibility: names of private and privately-inherited members are visible and considered by overload resolution, implicit conversions to inaccessible base classes are still considered, etc. Member access check is the last step after any given language construct is interpreted. The intent of this rule is that replacing any private with public never alters the behavior of the program.
下一段描述了您的示例所展示的行为:
Access rules for the names of virtual functions are checked at the call point using the type of the expression used to denote the object for which the member function is called. The access of the final overrider is ignored.
另请参阅 this answer 中列出的操作顺序.
没有。
而且我认为您永远无法这样做,因为这种行为并不违法。
澄清一下:这里的“决定”是指编译器在重载解析后检查访问限定符的规定。简短的回答:防止在更改代码时出现意外。
有关更多详细信息,我们假设您正在开发一些如下所示的 CoolClass
class CoolClass {
public:
void doCoolStuff(int coolId); // your class interface
private:
void doCoolStuff(double coolValue); // auxiliary method used by the public one
};
假设编译器可以根据公共(public)/私有(private)说明符进行重载解析。然后下面的代码将成功编译:
CoolClass cc;
cc.doCoolStuff(3.14); // invokes CoolClass::doCoolStuff(int)
// yes, this would raise the warning, but it can be ignored or suppressed
然后在某些时候您发现您的私有(private)成员函数实际上对类客户端有用并将其移至“公共(public)”区域。这会自动更改预先存在的客户端代码的行为,因为现在它调用CoolClass::doCoolStuff(double)
。
因此,应用访问限定符的规则是以不允许允许这种情况的方式编写的,因此您会在一开始就遇到“模棱两可的调用”编译器错误。出于同样的原因,虚函数也不是特例(参见 this answer)。
不是真的。通过将指向您的类的指针转换为指向其基类的指针,您实际上是在说:“在此我想使用这个对象 B,就好像它是一个对象 A”——这是完全合法的,因为继承意味着“按原样” "关系。
所以问题是,您的示例是否可以视为违反了基类规定的契约?好像是的,可以。
查看 this question 的答案其他解释。
不要误会我的意思,所有这些并不意味着您不应该使用私有(private)虚函数。相反,它通常被认为是一种好的做法,请参阅 this thread .但是它们应该从最基类是私有(private)的。所以,底线是,你不应该使用私有(private)虚函数来破坏公共(public)契约。
附言...除非您故意要强制客户端通过指向接口(interface)/基类的指针使用您的类。但是有更好的方法,我相信对这些的讨论超出了这个问题的范围。
关于c++ - 为什么覆盖虚函数时不考虑访问限定符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45671799/
我一直在使用 OpenGL 编写程序。最近,我开始学习OpenGL着色语言。我是新手;因此,请在回答中详细说明。 我的问题是: GLSL 中有哪些不同类型的变量(限定符)? 它们的用途是什么? 它们有
这个问题在这里已经有了答案: typedef pointer const weirdness (6 个答案) 关闭 8 年前。 我有一个结构体 type_s。然后我将指向 struct type_s
我有一个 Point2D 类如下: class Point2D{ int x; int y; public: Point2D(int inX,
当应用于指向指针的指针等时,我在推断什么是 const 时遇到了一些麻烦。即,什么是 const 当你有 const Foo **foo; 我可以在这里更改 **foo 中的内容吗?如 foo[0]
限定符 有时候不知道要匹配多少字符。为了能适应这种不确定性,正则表达式支持限定符的概念。这些限定符可以指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。 下表给出了各种限定符及其含义的说
我有一个包含字符名称的数组结构。我想使用 qsort 按字母顺序对它们进行排序,但是我一直收到一条错误消息,说“初始化丢弃了指针目标类型中的‘const’限定符”。我相信我的 cmpmi() 函数和
我是 Java EE/JSF 的新手,现在阅读 CDI 限定符 - 更改类实现的可能性。这很好,但我有一个问题。据我了解,我可以使用限定符更改类实现,但我需要在使用此实现的任何地方更改它。在一个地方进
假设我有以下目录结构: $ mkdir -p a/1 $ ln -s a b 查找目录,我也得到了符号链接(symbolic link)中的目录: $ print -l */*(/) a/1 b/1
我正在尝试创建一个 const 结构数组,但我不断得到 error initializer element is not a compile time constant 我使用的是keil IDE。这
#include using namespace std; class Point { private: int x, y; // Private data members public:
我想使一个方法有条件地成为常量。也就是说,我们有 template class A { // stuff }; 根据模板参数的值,要么 void method() const; 或 void
由于 const int 特化导致以下错误: #include using std::cout; using std::endl; template void g(T val) { cou
同时适用于移动设备和平板电脑的 Titanium 项目,完美地完成了移动版本,但在平板设计时面临一些复杂性。 下面是 Titanium 支持的限定符矩阵,但我找不到任何针对 Android-Table
我正在研究 C++ 和 gtkmm,试图创建一个自定义类,它调用 .glade 文件来构建一个 Gtk 而不是基本的界面。此类派生自 Gtk::Window,但是当我调用类本身的 get_widget
我编写了以下代码来测试 const 成员函数:当我有数据成员的 const 限定符时,它编译并运行良好char *data 和构造函数的参数。但是,如果我从中删除 const数据成员和构造函数,我得到
您好,我正在使用 C++ 内置算法。我这里有这段代码: #include #include #include using namespace std; bool isDon(string& na
我的问题与 Time 项目有关,我将在下面完整发布该项目以提供背景信息。我所做的大部分都是正确的,但是当涉及到加法和减法运算符定义时,我遇到了范围界定错误的问题。编译器找不到我的私有(private)
我有以下代码- int acb(const uint16 *MsgPtr) { uint16 *p = (MsgPtr + 1); printf("%d", *p); } 我收到以下警告 - 在为 p
我在结构中有一个指向结构实例链表的指针字段。 struct myStruct { some fields... struct list_objects * volatile list;
所以我在维基百科的一篇文章(粗略翻译)中遇到了以下定义: Modifier (programming) - element of source code being a phrase of given
我是一名优秀的程序员,十分优秀!