Cod*_*cks 2 c++ inheritance namespaces scope-resolution dot-operator
C++
给定基类Base
和派生类Derived
,构造函数构造的第一件事Derived
是Base
子对象.由于它被称为子对象,我认为可以通过在对象上使用点运算符从客户端代码访问它,就像任何其他成员对象一样Derived
.我还假设它可以通过Derived
实现代码访问this->Base
.完全由已经初始化后跟分号的对象的名称组成的语句应该编译但是也没有效果.继这一逻辑,给定一个Derived
目标myderived
,我想:myderived.Base;
在客户端代码和this->Base;
中Derived
的实现也不言编译.
为什么?我知道Base
,它本身就是Base
类的名称,而不是Base
对象的名称.但我认为Base
由myderived.
(客户端代码)或this->
(实现代码)前缀限定引用基础子对象,因为Base
没有任何前缀限定,是在构造函数初始化程序中Base
引用子对象的方式Derived
.请参阅下面的代码,其中(注释掉的代码旁边)适用于VC12和g ++ 4.8.Derived
extends Base
和Derived
的定义声明了一个Base
数据成员membase
,所以我的Derived
对象应该包含两个Base
对象.假设成功编译不是任何编译器 - 标准 - 不符合的结果,控制台输出(在注释中)显示两个不同对象的int
成员的不同值,意味着在's ctor初始化器中,指的是继承的子对象,而引用声明的数据成员对象.在's ctor初始化器中,具体指的是继承的子对象,而不仅仅是任何对象或类.n
Base
Derived
Base
Base
membase
Derived
Base
Base
Base
#include <iostream>
struct Base {
Base(int par) : n(par) {}
void foo() { std::cout << "Base: " << n << std::endl; }
int n;
};
struct Derived : Base {
Derived() : Base(2), membase(3) {}
Base membase;
void foo() { std::cout << "Derived: " << n << std::endl; }
// void g() { this->Base; } // Error in VC12 & g++ 4.8
// ^ VC12: error C2273: 'function-style cast' : illegal as
// right side of '->' operator
};
int main() {
Derived myderived;
// myderived.Base; //Error in VC12 & g++ 4.8
// ^ VC12: error C2274: 'function-style cast' : illegal as
// right side of '.' operator
myderived.foo(); // OUTPUT: "Derived: 2"
myderived.Base::foo(); // OUTPUT: "Base: 2"
myderived.membase.foo(); // OUTPUT: "Base: 3"
}
Run Code Online (Sandbox Code Playgroud)
再次,不应该myderived.Base;
或this->Base;
唯一地引用继承的Base
子对象并编译?
是否Base
在myderived.Base
或this->Base
指Base
子对象或Base
在所有类或什么?
一般来说,继承的基础子对象是否被认为是派生类的数据成员?
从角度来看Derived
,Base
只是在Derived
构造函数初始化程序的上下文中引用了继承的子对象,并且只引用了Base
外部Derived
的ctor初始化程序的类?
如何Base
通过Derived
对象访问继承的子对象,如,如何在实现代码和客户端代码中表达" Base
对象的继承子Derived
对象" Derived
?
在VC12和g ++ 4.8中使用范围解析运算符myderived.Base::foo()
,其中foo()
是一种方法Base
.这是否意味着它Base
是一个数据成员myderived
,因为它是由myderived
dot运算符限定的?如果是这样,那么是Base
的Base
类或Base
子对象?
但是myderived.Base.foo()
没有编译.对象成员的AFAIK访问权限由客户端代码通过对象名称和点运算符限定.由范围解析运算符限定的两种东西,而不是对象名称和点运算符,是(a)对属于命名空间的任何东西的外部访问,以及(b)静态数据成员的名称和成员函数的名称在类定义之外定义的定义,在这种情况下Base
,在::
引用Base
类之前,而不是任何Base
实例.这是否意味着Base
in myderived.Base
是命名空间或引用类?
如果是这样,那么它是一个命名空间还是引用该类的条件是它是否附加一个::
后跟一个成员Base
?
如果对#7的答案是肯定的,为什么呢?这与以下逻辑似乎不协调:命名空间的一个变量的封闭本身不能使命名空间包含或构造变量类型的其他实例.命名空间只拥有该类型的一个实例 - 它包含的变量.对于属于类的成员,例如静态数据成员,也是如此.该类只拥有该类型的一个实例 - 它包含的静态数据成员.相比之下,类的实例与该类的实例一样多,同名的非静态数据成员.
给定方法h()
的Base
和一个Derived
对象myderived
,myderived.Base::h();
编译在VC12和g ++ 4.8.另外,g ++ 4.8可以Base::
在该语句中使用任意数量的额外s,例如myderived.Base::Base::h();
.这样的陈述似乎暗示Base
是一个成员Base
.但VC12给出了error C3083: '{ctor}': the symbol to the left of a '::' must be a type
.但是给定Base
对象mybase
,VC12编译mybase.Base::h();
得很好,这也意味着VC12可以将一个类视为自身的一员.但这与其无法编制先前的陈述相矛盾.此外,VC12无法编译mybase.Base::h();
具有任何数量的额外Base::
s(例如mybase.Base::Base::h()
)的任何版本,但g ++可以.哪个编译器是正确的,如果有的话?
在任何情况下,这是否意味着命名空间或类可以包含自己?给定一个全局int
变量x
,该语句::::x;
(带有两个作用域解析运算符)不能在任何一个编译器中编译,因此我假设全局作用域不包含全局作用域.
Base
与Base
子对象分开的成员.的::
标点限制名称解析忽略成员的对象名称.Base
本身是继承自的Base
.如果您有一个疯狂的成员别名,那么您需要使用一些其他引用,Base
例如名称空间限定的id.static_cast< Base & >( derived_obj )
.::
优先级高于.
使Base::foo
部件内部查找myderived
,然后应用函数调用操作符.但是不允许使用parens,(Base::foo)
因为::
它不是生成子表达式的运算符; 这就是为什么我更喜欢把它称为标点符号.myderived.Base
不是什么东西本身,因为::
以前的基地组.
.static
类中,成员和命名空间成员是完全独立的对象,可以在任何地方定义.Base::Base::Base::
因为一个类的名称被注入其自身,就好像它是一个成员一样typedef
.VC可能会出错并将其解释为对构造函数的引用.根据规范,特殊的typedef(称为inject-class-name)是指特殊情况下的构造函数,但在作用域运算符不是这种情况之前.每个类都包含一个隐含的东西typedef
.同样,名称空间和类是完全不同的东西.
前缀::
本身不是全局命名空间的名称,而只是语法中的一个特殊情况,以补偿其缺少名称.同样,无论好坏,你都无法申报
namespace global = :: ; // error: :: alone does not name anything.
Run Code Online (Sandbox Code Playgroud)