- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
当涉及使用和/或省略 template
的 4 种组合时,我想了解访问修饰符关于继承的 4 种不同行为s 和 this
关键词。以下所有代码均在 g++ 4.8 中完成:
这是一个 GrandChild
类,private
ly 继承自 Parent
,这private
ly 继承自 GrandParent
, 它有一个 public
enum
n
.非对象,客户端代码可以访问GrandParent::n
, 因为后者是 public
enum
.但是GrandParent::n
无法从内部访问 GrandChild
:
#include <iostream>
using namespace std;
struct GrandParent { enum {n = 0}; };
struct Parent : private GrandParent { enum {n = 1}; };
struct GrandChild : private Parent {
enum {n = 2};
void f() {cout << GrandParent::n << endl;}
// ^ error: 'struct GrandParent GrandParent::GrandParent'
// is inaccessible
};
int main() {
cout << GrandParent::n << endl;
// ^ non-object access would have outputted `0` had `GrandChild`'s
// definition compiled or been commented out.
}
1.) 是 GrandParent::n
从内部无法访问 GrandChild
由 GrandChild
引起拥有一个GrandParent
基础子对象,它隐藏了对 GrandParent::num
的非对象访问, 以及其 2 代 private
ness 使基础子对象的 n
也无法访问?我原以为错误消息与此有关。
2.) 但显然,事实并非如此。为什么报错GrandParent
的构造函数?
3.) 前置this->
至 GrandParent::n
在 f()
的定义将添加我在 #1 中预期的错误,但不会删除 ctor 投诉。 为什么? 我假设包括 this->
是多余的,它的遗漏将导致查找试图找到 n
的 GrandParent
GrandChild
中的子对象在 less-immediately-scoped 非对象之前的范围 n
无论如何。
4.) 为什么这个模板变体可以编译?它看起来在功能上类似于非模板:
#include <iostream>
using namespace std;
template <unsigned int N>
struct bar : private bar<N - 1> {
enum {num = N};
void g() {
static_assert(N >= 2, "range error");
cout << bar<N - 2>::num << endl;
}
};
template <>
struct bar<0> { enum {num = 0}; };
int main() {
bar<2> b2;
b2.g(); // Output: 0
}
5.) 前置this->
至 bar<N - 2>::num
在 g()
的定义只导致我在#1 中预期的编译器错误。但是为什么它不包含#2 的错误呢?为什么它的遗漏不会产生 #2 的错误?
最佳答案
这里的整个问题是名称查找(我认为情况也是如此 in one of your previous questions )。我将尝试说明我对正在发生的事情的理解:
每个(命名的)类都有一个注入(inject)类名。例如:
struct GrandParent
{
// using GrandParent = ::GrandParent;
enum {n = 0};
};
您可以使用这个注入(inject)类名来引用类本身。它对普通类没有多大用处(非限定查找无论如何都可以在周围范围内找到名称 GrandParent
),但对于派生类和类模板:
namespace A
{
struct Foo
{
// using Foo = ::A::Foo;
};
};
struct Bar : A::Foo
{
void woof(Foo); // using the injected-class-name `::A::Foo::Foo`
};
template<class T, int N, bool b>
struct my_template
{
// using my_template = ::my_template<T, N, b>;
void meow(my_template); // using the injected-class-name
};
这不是“它是基类子对象的一部分”中的继承,而是指定非限定查找的方式:如果在当前类的作用域中找不到该名称,则将搜索基类作用域。
现在,对于 OP 中的第一个(非模板)示例:
struct Parent : private GrandParent
{
// using Parent = ::Parent;
enum {n = 1}; // hides GrandParent::n
};
struct GrandChild : private Parent {
// using GrandChild = ::GrandChild;
enum {n = 2};
void f() {cout << GrandParent::n << endl;}
// ^ error: 'struct GrandParent GrandParent::GrandParent'
// is inaccessible
};
在这里,表达式 GrandParent::n
调用名称 GrandParent
的非限定名称查找.由于非限定查找在找到名称时停止(并且不考虑周围的范围),它将找到注入(inject)的类名 GrandParent::GrandParent
.也就是说,lookup 搜索 GrandChild
的范围。 (未找到名称),然后是 Parent
的范围(未找到名称)最后是 GrandParent
的范围(它找到注入(inject)类名的地方)。这是之前并且独立于访问检查完成的。
名字后GrandParent
已找到,最终检查可访问性。需要从 Parent
进行名称查找至 GrandParent
找到名字。除 Parent
的成员和 friend 外,此路径对任何人都被阻止,因为继承是私有(private)的。 (您可以看穿那条路径,但您可能不会使用它;可见性和可访问性是正交的概念。)
这是标准 [basic.lookup.unqual]/8:
For the members of a class
X
, a name used in a member function body [...] shall be declared in one of the following ways:
- before its use in the block in which it is used or in an enclosing block, or
- shall be a member of class
X
or be a member of a base class ofX
, or- if
X
is a nested class of classY
[...]- [...]
- if
X
is a member of namespaceN
, or [...], before the use of the name, in namespaceN
or in one ofN
’s enclosing namespaces.
基类中的名称查找相当复杂,因为可能必须考虑多个基类。对于单继承,在成员函数体范围内查找成员,从该函数所属的类开始,向上遍历基类(base, base of base, base of base of base, ..).参见 [class.member.lookup]
模板大小写不同,如bar
是类模板的名称:
template <unsigned int N>
struct bar : private bar<N - 1> {
enum {num = N};
void g() {
static_assert(N >= 2, "range error");
cout << bar<N - 2>::num << endl;
}
};
在这里,bar<N - 2>
用来。它是一个从属名称,如 N
是模板参数。因此,名称查找被推迟到 g
的实例化点。 .特化bar<0>
可以找到,即使它是在函数之后声明的。
bar
的注入(inject)类名可以用作模板名(指类模板)或类型名(指当前实例化) [temp.local]/1:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected- class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type- specifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in
<>
.
即bar<N - 2>
发现 bar
作为当前类的注入(inject)类名(实例化)。因为它与 template-argument-list 一起使用,所以它指的是 bar
的另一个不相关的特化。 .基类的注入(inject)类名是隐藏的。
bar<0>::num
不是通过私有(private)继承的访问路径访问,而是直接通过当前类的注入(inject)类名,引用类模板本身。 num
成为 bar<0>
的公共(public)成员是可访问的。
关于c++ - 访问修饰符在继承中的不同行为取决于 "this"关键字和模板或缺少它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20808993/
我正在尝试在 map 上绘制一些疾病事件数据的位置。 我用它来导入数据: ByTown% addProviderTiles("CartoDB.Positron")%>% addPolygons
我有一个文件调用 find.js,我使用 node find.js 运行,我的节点是版本 10 我不知道为什么我无法使用 async await。 const axios = require("axi
我有一个项目作为引用添加到 System.Web。 但是,它似乎无法获取 HttpContext。这样做: Imports System.Web _ApplicationBase = HttpCont
在互联网上找到这段代码,出于某种原因它缺少 while 循环逻辑“while(i....)”,虽然我找到了 PigLatin* 问题的其他可行解决方案,但我真的很想了解这个正在工作。 *PigLati
我工作了一整天来运行 Xampp 并在其上安装 TYPO3。现在我登录到后端,但没有显示许多管理模块,例如模板、访问等。 - 一定是我做错了什么,但我不知道。 these are the module
你好 我有编译这个问题 \begin{equation} J = \sum_{j=1}^{C} \end{equation} 我不断收到错误 missing $ inserted 这很奇怪,因
我正在尝试使用 SQLite CLI,但无法获得 generate_series功能来工作。我可以按照文档中的建议使用递归 CTE 对其进行模拟,但我似乎无法获得该链接中的任何示例。这是我的 sess
我目前正在开发我想要的软件,而软件正在安装,它可以在后台为软件创建 native 图像。 我正在考虑使用 NGEN 并将进程优先级设置为低,因为我不希望它消耗 100% CPU。但是我发现我的计算机上
我想使用 Xcodes Instruments 进行 UI 自动化测试。但似乎缺少“自动化”。我怎样才能添加这个? 最佳答案 如果您想使用自动化仪器,请使用 Xcode 7.3。 Apple 在 Xc
我目前在 JS 开发中迈出了一小步,并编写了以下链接添加器: const button = document.getElementById('button') const listdiv = docu
此代码有什么问题: NSError *error = nil; [SFHFKeychainUtils deleteItemForUsername:@"IAPNoob01" andServiceName
出于某种原因,在安装和配置(我认为)一切之后,com.adobe.utils.AGALMiniAssembler 不见了,其他一切正常。 我认为我已尽一切努力让孵化器正常工作,但显然我错过了一步。 如
我有一个名为 new 的方法。调用 new 时,我传递了一个参数,但是当我运行应用程序时,出现没有参数或参数为空的错误。 StepReader.pm package StepReader; use s
安装 gtk 1.2(包名 gtk1)和 macports chokes 在最终的 make 中,在 libintl.h 的第 440 行。 extern locale_t libintl_newlo
我用按钮创建表格。 这是javascript代码: function layersListTable(layers) { var content =''; $.each($(layer
我在使用此 javascript 时遇到此错误,任何人都可以帮我弄清楚我做错了什么吗? $(this).prepend('Check availability »'); 它给我错误 mis
我有一个独立的工具链 NDK13b、api19、llvm 3.8 编译器、arm 32 位、带有 libcpp(llvm C++ 库) 我想避免依赖 libgcc,所以我构建了 compiler-rt
我按照一些教程使用 phonegap 的条形码扫描器插件。但是当我从现有源创建一个新的 android 项目来创建条码库时 (step 6 in this page)我收到错误:“AndroidMan
我现在尝试在 Eclipse 中打开我的布局 xml 文件。我只得到错误 No XML content. Please add a root view or layout to your docume
我的 android-sdk-windows\tools 目录中缺少层次结构查看器工具。 工具链接: http://developer.android.com/guide/developing/too
我是一名优秀的程序员,十分优秀!