Оператор точки или стрелки или оператор разрешения области для доступа к базовому подобъекту

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"}
  1. Опять не должен myderived.Base; или же this->Base; однозначно относиться к наследственному Base подобъект и компилировать?

  2. Ли Base в myderived.Base или же this->Base обратитесь к Base подобъект или Base класс или что-нибудь вообще?

  3. В общем, считаются ли унаследованные базовые подобъекты членами данных производных классов?

  4. С точки зрения Derivedделает Base обращаться только к унаследованному подобъекту в контексте DerivedИнициализатор конструктора и ссылаются только на Base класс снаружи DerivedИнициализатор ctor?

  5. Как я могу получить доступ к унаследованному Base подобъект через Derived объект, как в, как я могу выразить «унаследованный Base подобъект Derived объект »в DerivedКод реализации и код клиента?

  6. Использование оператора разрешения области в myderived.Base::foo(), где foo() это метод Base, компилирует в VC12 и g ++ 4.8. Это значит Base является членом данных myderivedпоскольку он квалифицирован myderived а точечный оператор? Если так, то это Base Base класс или Base подобъекте?

  7. Но myderived.Base.foo() не компилируется. AFAIK-доступ к элементу объекта определяется в клиентском коде с помощью имени объекта и оператора точки. Оператор разрешения области видимости квалифицирует два вида вещей вместо имени объекта и оператора точки: (а) внешний доступ ко всему, что принадлежит пространству имен, и (б) имена членов статических данных и имена функций-членов определений, определенных вне определения их класса, и в этом случае Base что предшествует :: относится к Base класс, а не любой Base пример. Означает ли это Base в myderived.Base такое пространство имен или относится к классу?

  8. Если это так, то является ли оно пространством имен или ссылается на класс в зависимости от того, добавляется ли оно :: сопровождаемый членом Base?

  9. Если ответ на вопрос № 7 — да, то почему? Это может показаться несовместимым со следующей логикой: вложенность пространства имен в одну переменную сама по себе не позволяет пространству имен включать или создавать другие экземпляры типа переменной. Пространству имен принадлежит только один экземпляр этого типа — переменная, которую он содержит. То же самое относится и к члену, который является частью класса, например, к члену статических данных. Классу принадлежит только один экземпляр этого типа — статический член данных, который он содержит. В отличие от этого, существует столько же нестатических членов данных с тем же именем, что и экземпляров класса.

  10. Данный метод 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 ++ может. Какой компилятор правильный, если есть?

  11. В любом случае, означает ли это, что пространство имен или класс могут содержать себя? Учитывая глобальный int переменная x, заявление ::::x; (с двумя операторами разрешения контекста) не компилируется ни в одном компиляторе, поэтому я предполагаю, что глобальная область не содержит глобальную область.

2

Решение

  1. Нет, вы можете иметь члена с именем Base который отделен от Base субобъект. :: пунктуатор ограничивает разрешение имен, чтобы игнорировать имя объекта члена.
  2. Смотрите № 1. Обычно ответ отрицательный, потому что вы бы с ума сошли, если бы псевдоним участника был специально создан. Но это может случиться с шаблонами, где класс может не знать имен своих баз.
  3. Нет. Подобъекты-члены и базовые подобъекты являются подобъектами, но к ним обращаются по-разному.
  4. Это всегда относится к классу и имени Base сам унаследован от Base, Если у вас есть сумасшедший псевдоним участника, то вам нужно использовать другую ссылку на Base такой как идентификатор пространства имен
  5. static_cast< Base & >( derived_obj ),
  6. Нет, :: имеет более высокий приоритет, чем . Итак Base::foo член смотрит внутрь myderived и затем применяется оператор вызова функции. Однако нельзя брать с собой паренов (Base::foo) так как :: не является оператором, генерирующим подвыражение; Вот почему я предпочитаю называть это пунктуатором.
  7. Смотрите № 6. myderived.Base само по себе ничего не значит, потому что базовые группы с :: до .,
  8. Правильно. Обратите внимание, что классы не являются пространствами имен; это разные вещи, которые оба работают с одной и той же нотацией области видимости.
  9. Кажется, это объясняет C ++ в терминах, которые могут применяться к другому языку. Например, в Java класс является своего рода объектом с собственными членами данных. В C ++ static члены класса и члены пространства имен являются совершенно отдельными объектами, которые могут быть определены где угодно.
  10. Base::Base::Base:: работает, потому что имя класса вводится в себя, как если бы он был членом typedef, VC, вероятно, делает ошибку и интерпретирует ее как ссылку на конструктор. Согласно спецификации, специальный typedef (называется нагнетаемого имя класса) ссылается на конструктор при особых обстоятельствах, но до того, как оператор не такой случай.
  11. Каждый класс содержит неявный typedef к себе. Опять же, пространства имен и классы — это совершенно разные вещи.

    Префикс :: само по себе не является именем глобального пространства имен, а просто особым случаем в грамматике, чтобы компенсировать его отсутствие имени. Точно так же, к лучшему или худшему, вы не можете объявить

    namespace global = :: ; // error: :: alone does not name anything.
    
8

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]