С++: доступ к родительским методам и переменным

В каком порядке я должен получить доступ к этому родительскому методу и родительской переменной?

class Base
{
public:
    std::string mWords;
    Base() { mWords = "blahblahblah" }
};

class Foundation
{
public:
    Write( std::string text )
    {
        std::cout << text;
    }
};

class Child : public Base, public Foundation
{
    DoSomething()
    {
        this->Write( this->mWords );
        // or
        Foundation::Write( Base::mWords );
    }
};

Спасибо.

Изменить: А что, если есть двусмысленность?

Ответ 1

Два синтаксиса, которые вы используете в своем коде (this->... и квалифицированные имена), необходимы только тогда, когда есть проблема двусмысленности или какой-либо другой проблемы поиска имен, например, скрытие имени, базовый класс шаблона и т.д.

Если нет никакой двусмысленности или других проблем, вам не нужен какой-либо из этих синтаксисов. Все, что вам нужно, это простое неквалифицированное имя, например Write в вашем примере. Просто Write, а не this->Write, а не Foundation::Write. То же самое относится к mWords.

т.е. в вашем конкретном примере простая Write( mWords ) будет работать нормально.


Чтобы проиллюстрировать это, если у вашего метода DoSomething был параметр mWords, как в

DoSomething(int mWords) {
  ...

то этот локальный параметр mWords скроет унаследованный член класса mWords, и вам придется использовать либо

DoSomething(int mWords) {
  Write(this->mWords);
}

или

DoSomething(int mWords) {
  Write(Foundation::mWords);
}

чтобы выразить свое намерение правильно, т.е. прорваться через скрытие.


Если ваш класс Child также имеет свой собственный член mWords, как в

class Child : public Base, public Foundation
{
  int mWords
  ...

то это имя скроет унаследованный mWords. Подход this->mWords в этом случае не поможет вам отобразить собственное имя, и вам придется использовать квалифицированное имя для решения проблемы.

DoSomething(int mWords) {
  Write(Foundation::mWords);
}

Если оба базовых класса имели член mWords, как в

class Base {
public:
  std::string mWords;
  ...
};

class Foundation {
public:
  int mWords;
  ...

то в Child::DoSomething имя mWords будет неоднозначным, и вам нужно будет сделать

DoSomething(int mWords) {
  Write(Foundation::mWords);
}

для устранения двусмысленности.


Но, опять же, в вашем конкретном примере, где нет никакой двусмысленности и скрытия имени, все это совершенно не нужно.

Ответ 2

Я думаю, что это самый распространенный подход:

Write(mWords);

если вы не столкнетесь с двусмысленностью.

Если существует двусмысленность или затенение, потому что вы хотите что-то в (конкретном) базовом классе, но что-то в другом базовом классе (или этом классе) скрывает его, используйте синтаксис Base::name.

Если локальная переменная затеняет один из ваших членов, используйте this->, хотя в целом вы должны попытаться избежать этой ситуации. (т.е. старайтесь избегать именования локалей, чтобы они теневые члены)

Я предполагаю, что один из способов взглянуть на это - это использовать первое из них, которое работает и делает то, что вы хотите:

  • name
  • this->name
  • Base::name

Ответ 3

Так как нет конфликта имен, просто используйте Write(mWords). Используйте другие 2, если у вас есть локальные переменные, которые конфликтуют, или когда имена скрыты.