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
продолжается Base
а также Derived
Определение объявляет Base
элемент данных membase
, Так что мой Derived
объект должен содержать два Base
объекты. Предполагая, что успешная компиляция не является результатом какого-либо несоответствия стандартного компилятора, вывод консоли (в комментариях), который показывает различные значения для int
члены n
для двух разных Base
объекты, подразумевает, что в Derived
Инициализатор ctor, Base
относится к наследственному Base
подобъект в то время как membase
ссылается на объявленный объект-член данных. В Derived
Инициализатор ctor, 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
Инициализатор конструктора и ссылаются только на Base
класс снаружи Derived
Инициализатор ctor?
Как я могу получить доступ к унаследованному Base
подобъект через Derived
объект, как в, как я могу выразить «унаследованный Base
подобъект Derived
объект »в Derived
Код реализации и код клиента?
Использование оператора разрешения области в myderived.Base::foo()
, где foo()
это метод Base
, компилирует в VC12 и g ++ 4.8. Это значит Base
является членом данных myderived
поскольку он квалифицирован myderived
а точечный оператор? Если так, то это Base
Base
класс или Base
подобъекте?
Но myderived.Base.foo()
не компилируется. AFAIK-доступ к элементу объекта определяется в клиентском коде с помощью имени объекта и оператора точки. Оператор разрешения области видимости квалифицирует два вида вещей вместо имени объекта и оператора точки: (а) внешний доступ ко всему, что принадлежит пространству имен, и (б) имена членов статических данных и имена функций-членов определений, определенных вне определения их класса, и в этом случае Base
что предшествует ::
относится к Base
класс, а не любой Base
пример. Означает ли это Base
в myderived.Base
такое пространство имен или относится к классу?
Если это так, то является ли оно пространством имен или ссылается на класс в зависимости от того, добавляется ли оно ::
сопровождаемый членом Base
?
Если ответ на вопрос № 7 — да, то почему? Это может показаться несовместимым со следующей логикой: вложенность пространства имен в одну переменную сама по себе не позволяет пространству имен включать или создавать другие экземпляры типа переменной. Пространству имен принадлежит только один экземпляр этого типа — переменная, которую он содержит. То же самое относится и к члену, который является частью класса, например, к члену статических данных. Классу принадлежит только один экземпляр этого типа — статический член данных, который он содержит. В отличие от этого, существует столько же нестатических членов данных с тем же именем, что и экземпляров класса.
Данный метод h()
из Base
и Derived
объект myderived
, myderived.Base::h();
компилирует в VC12 и g ++ 4.8. Addionally, g ++ 4.8 может принять любое произвольное количество дополнительных Base::
в этом заявлении, как 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
такой как идентификатор пространства именstatic_cast< Base & >( derived_obj )
,::
имеет более высокий приоритет, чем .
Итак Base::foo
член смотрит внутрь myderived
и затем применяется оператор вызова функции. Однако нельзя брать с собой паренов (Base::foo)
так как ::
не является оператором, генерирующим подвыражение; Вот почему я предпочитаю называть это пунктуатором.myderived.Base
само по себе ничего не значит, потому что базовые группы с ::
до .
,static
члены класса и члены пространства имен являются совершенно отдельными объектами, которые могут быть определены где угодно.Base::Base::Base::
работает, потому что имя класса вводится в себя, как если бы он был членом typedef
, VC, вероятно, делает ошибку и интерпретирует ее как ссылку на конструктор. Согласно спецификации, специальный typedef (называется нагнетаемого имя класса) ссылается на конструктор при особых обстоятельствах, но до того, как оператор не такой случай.Каждый класс содержит неявный typedef
к себе. Опять же, пространства имен и классы — это совершенно разные вещи.
Префикс ::
само по себе не является именем глобального пространства имен, а просто особым случаем в грамматике, чтобы компенсировать его отсутствие имени. Точно так же, к лучшему или худшему, вы не можете объявить
namespace global = :: ; // error: :: alone does not name anything.
Других решений пока нет …