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