C++
Given a base class Base
and a derived class Derived
, the first thing constructed by Derived
’s constructor is the Base
subobject. Since it’s called a subobject, I assumed it can be accessed from client code like any other member object by using the dot operator on the Derived
object. I also assumed it can be accessed from Derived
’s implementation code by this->Base
. A statement comprised entirely of the name of an object that has already been initialized followed by a semicolon should compile but also have no effect. Following that logic, given a Derived
object myderived
, I tried: myderived.Base;
in client code and this->Base;
in Derived
’s implementation and neither statement compiles.
Why? I know Base
, by itself, is the name of the Base
class and not of a Base
object. But I thought Base
qualified by the myderived.
(client code) or this->
(implementation code) prefix refers to the base subobject because Base
, without any prefix qualifications, is the way the Base
subobject is referred to in Derived
’s constructor initializer. Refer to the below code, which (commented-out code aside) works in VC12 and g++ 4.8. Derived
extends Base
and Derived
’s definition declares a Base
data member membase
, so my Derived
object should contain two Base
objects. Assuming the successful compilation isn’t the result of any compiler-Standard-nonconformity, the console output (in the comments), which shows different values for the int
members n
for the two different Base
objects, implies that in Derived
’s ctor initializer, Base
refers to the inherited Base
subobject whereas membase
refers to the declared data member object. In Derived
’s ctor initializer, Base
refers specifically to the inherited subobject, not just any Base
object nor the Base
class.
#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"
}
Again, shouldn’t
myderived.Base;
orthis->Base;
uniquely refer to the inheritedBase
subobject and compile?Does the
Base
inmyderived.Base
orthis->Base
refer to theBase
subobject or theBase
class or anything at all?In general, are inherited base subobjects considered data members of derived classes?
From the perspective of
Derived
, doesBase
only refer to the inherited subobject within the context ofDerived
’s constructor initializer and only refer to theBase
class outsideDerived
’s ctor initializer?How can I access the inherited
Base
subobject through theDerived
object, as in, how can I express “the inheritedBase
subobject of theDerived
object” inDerived
’s implementation code and in client code?The use of the scope resolution operator in
myderived.Base::foo()
, wherefoo()
is a method ofBase
, compiles in VC12 and g++ 4.8. Does this meanBase
is a data member ofmyderived
, since it is qualified bymyderived
and the dot operator? If so, then is thatBase
theBase
class or theBase
subobject?But
myderived.Base.foo()
doesn’t compile. AFAIK access of an object’s member is qualified in client code by the object name and dot operator. Two kinds of things that are qualified by the scope resolution operator, instead of the object name and dot operator, are (a) outside access to anything that belongs to a namespace and (b) the names of static data members and names of member functions of definitions defined outside their class definition, in which case theBase
that precedes the::
refers to theBase
class, not anyBase
instance. Does this mean theBase
inmyderived.Base
is a namespace or refers to the class?If so, then is its being a namespace or referring to the class conditional upon whether it is appended by a
::
followed by a member ofBase
?If the answer to #7 is yes, then why? It would seem incongruous with the following logic: a namespace’s enclosure of one variable does not in itself enable the namespace to enclose or construct other instances of the variable’s type. The namespace only owns one instance of that type--the variable it encloses. The same goes for a member that is part of a class, as in, static data member. The class only owns one instance of that type--the static data member it encloses. In contrast, there are as many same-named non-static data members of a class as there are instances of the class.
Given method
h()
ofBase
and aDerived
objectmyderived
,myderived.Base::h();
compiles in VC12 and g++ 4.8. Addionally, g++ 4.8 can take any arbitrary number of extraBase::
s in that statement, likemyderived.Base::Base::h();
. Such a statement seems to implyBase
is a member ofBase
. But VC12 giveserror C3083: '{ctor}': the symbol to the left of a '::' must be a type
. But givenBase
objectmybase
, VC12 compilesmybase.Base::h();
just fine, which would also imply VC12 is fine with treating a class as a member of itself. But that contradicts its inability to compile the prior statement. Also, VC12 cannot compile any version ofmybase.Base::h();
that has any number of extraBase::
s (e.g.mybase.Base::Base::h()
), but g++ can. Which compiler is correct, if any?In any case, does that mean a namespace or class can contain itself? Given a global
int
variablex
, the statement::::x;
(with two scope resolution operators) doesn’t compile in either compiler, so I’m assuming the global scope doesn’t contain the global scope.