2017-01-25 2 views
0

Это было время, так как я использовал наследование C++, и мне интересно, если кто-то может прояснить и объяснить мне кое-что:разница между c.foo() и c.parent :: Foo()

class parent { 
    public: 
    int count; 
    parent() : count(0) {} 
    void increase_count() {count++;} 
    void print_count() {printf("Count: %d\n", count);} 
}; 

class child : public parent { 
    private: 
    int other; 
    public: 
    child() : other(0) {} 
}; 

int main (int argc, char *argv[]) { 

    child c; 
    for (int i = 0; i < 5; i++) { 
    c.print_count(); 
    c.increase_count(); 
    } 

    for (int i = 0; i < 5; i++) { 
    c.parent::print_count(); 
    c.parent::increase_count(); 
    } 
} 

Похоже, что c.<parent_function>() и c.parent::<parent_function>() - это то же самое. Этот синтаксис существует только для множественного наследования? Или есть какой-то нюанс, где даже без множественного наследования спецификатор области parent:: будет другим?

EDIT: Извините, но я должен был также предусмотреть ребенка, не имеющего метода с тем же именем.

+2

Попробуйте сделать 'print_count' виртуальной и перегрузки его в' child', то вы увидите разницу. –

+0

Использование квалифицированного имени метода в вызове будет подавлять полиморфизм, если метод является виртуальным. Но в вашем примере это не имело значения. – AnT

+0

Прошу прощения, я хотел также указать, что у ребенка нет метода с тем же именем, но я забыл его включить. – dbeer

ответ

3

Похоже, что c.() И c.parent: :() являются одинаковыми.

Они такие же, только если child не имеет функции с тем же именем.

Этот синтаксис существует только для множественного наследования?

Нет. Есть моменты, когда вам нужно вызвать реализацию функции в родительском классе.

Или существует какой-то нюанс, где даже без множественного наследования спецификатор parent :: scope был бы другим?

Да.

Пример:

#include <iostream> 

class parent { 
    public: 
     virtual void print() const 
     { 
     std::cout << "In parent::print()\n"; 
     } 

}; 

class child : public parent { 
    public: 
     virtual void print() const 
     { 
     std::cout << "In child::print()\n"; 
     } 
}; 

void print(parent& p) 
{ 
    p.print(); // Goes to child::print() when p references a child 
    p.parent::print(); // Goes to parent::print() regardless 
} 

int main() 
{ 
    child c; 
    print(c); 
} 

Выход

In child::print() 
In parent::print() 

Кроме того, бывают случаи, когда вам нужно ссылаться на реализацию родителя о функции virtual члена от реализации ребенка.

Пример:

#include <iostream> 

class parent { 
    public: 
     virtual void save(std::ostream& out) const 
     { 
     // Save the data corresponding to this class. 
     } 

}; 

class child : public parent { 
    public: 
     virtual void save(std::ostream& out) const 
     { 
     // Save the data corresponding to parent first. 
     parent::save(out); 

     // Save the data corresponding to this class. 
     } 
}; 

void save(parent& p, std::ostream& out) 
{ 
    p.save(std::cout); // Calls child::save() when p references a child, 
         // which in turn calls parent::save() 
} 

int main() 
{ 
    child c; 
    save(c, std::cout); 
} 
+1

На самом деле виртуальный ничего не меняет в этом примере – Slava

+0

@Slava, true. Это имело бы значение только в том случае, если функции вызывались через «parent &» или «parent *». –

+1

Правильно, вы можете добавить функцию, которая принимает ссылку на «parent» и вызывает «print» в обоих направлениях, чтобы иметь смысл использовать «virtual». – Slava

0

Если ваш производный класс имел перегрузку для родительской функции, то он «спрятал» функцию родителя, и вам нужно либо использовать указанный вами синтаксис, либо использовать инструкцию «using».

Вы можете увидеть пример в этом посте: Reason for C++ member function hiding

1

Вам не нужно множественное наследование или полиморфизм, чтобы продемонстрировать разницу. В самом простом:

struct B { 
    int foo() { return 0; } 
}; 

struct D : B { 
    int foo() { return 1; } 
}; 

Учитывая D, будет 1 и d.B::foo() будет 0. Синтаксис просто существует явно указать, какие функции члена вы хотите позвонить.

0

Вы должны использовать уточненное имя функции, когда существует неясность или вам необходимо вызвать определенную функцию.

Вот один неочевидный пример, тогда требуется квалифицированное имя.

#include <iostream> 

struct A 
{ 
    operator int() const { return 10; } 
    friend void output(const A &) 
    { 
     std::cout << "friend void output" << std::endl; 
    } 
}; 

void output(int) 
{ 
    std::cout << "void ::output" << std::endl; 
} 

int main() 
{ 
    output(A()); 
    ::output(A()); 

    return 0; 
} 

Выход программы

friend void output 
void ::output 

Класс А имеет друга функцию output с параметром типа const A & .. Если писать так, как написано в программе

output(A()); 

то функция friend будет вызвана из-за зависимого от аргумента поиска.

Однако, если вы хотите вызвать вторую функцию с параметром типа int, вам необходимо указать квалифицированное имя.

::output(A()); 

В противном случае будет вызываться функция друга.

Хотя в этом примере нет функций-членов, тем не менее функция friend определена в пределах класса. Он невидим вне класса и может быть выбран только из-за зависимого от аргумента поиска, когда объект класса указан как аргумент.

На самом деле этот вызов

output(A()); 

можно себе представить, как

A::output(A()); 

напротив вызова

::output(A()); 
Смежные вопросы