Коли я використовую крапку, стрілку або подвійну двокрапку для позначення членів класу на C ++?


243

Виходячи з інших мов C походження (наприклад , Java або C #) на C ++, то в першу дуже заплутані , що C ++ має три способи звернутися до членів класу: a::b, a.b, і a->b. Коли я використовую, хто з цих операторів?

(Примітка. Це призначено для запису до C ++ FAQ Stack Overflow . Якщо ви хочете критикувати ідею надання поширених запитань у цій формі, тоді це слід зробити публікацією на мета, яка почала все це . Відповіді на це питання контролюється в кімнаті чатів C ++ , де ідея FAQ задається в першу чергу, тому велику ймовірність отримати відповідь ті, хто придумав цю ідею.)

Відповіді:


248

Три окремі оператори, які C ++ використовує для доступу до членів класу або об’єкта класу, а саме подвійну двокрапку ::, крапку .та стрілку ->, використовуються для трьох різних сценаріїв, які завжди добре визначені. Знаючи це дозволяє відразу дізнатися досить багато про aі bпросто, подивившись на a::b, a.bабо a->b, відповідно, в будь-якому коді , ви дивитеся на.

  1. a::bвикористовується лише якщо bє членом класу (або простору імен) a. Тобто в цьому випадку aзавжди буде ім’я класу (або простору імен).

  2. a.bвикористовується лише у тому випадку, якщо bє членом об'єкта (або посиланням на об'єкт) a. Отже a.b, aзавжди буде фактичним об'єктом (або посиланням на об'єкт) класу.

  3. a->bце спочатку коротке позначення для (*a).b. Однак ->це єдиний з операторів доступу учасників, який може бути перевантажений, тому, якщо aце об'єкт класу, який перевантажує operator->(поширені такі типи - розумні покажчики та ітератори), то сенс у тому, який би конструктор класу не реалізував. На закінчення: З a->b, якщо aце вказівник, bбуде членом об'єкта, на який вказує вказівник a. Якщо, однак, aє об'єкт класу, який перевантажує цього оператора, тоді функція перевантаженого оператора operator->()викликається.


Дрібний друк:

  • У C ++, типи оголошені class, structабо unionвважаються «типу класу». Отже, вище стосується всіх трьох.
  • Посилання є семантично псевдонімами до об'єктів, тому я також повинен був додати "або посилання на покажчик" до №3. Однак я подумав, що це буде більш заплутаним, ніж корисним, оскільки посилання на покажчики ( T*&) рідко використовуються.
  • Оператори крапок і стрілок можуть використовуватися для позначення членів статичного класу від об'єкта, навіть якщо вони не є членами об'єкта. (Дякую Олі за вказівку на це!)

10
Це , можливо , слід уточнити , що .і ->може також використовуватися для доступу класу статики через об'єкт, навіть якщо вони не строго «члени об'єкта».
Олівер Чарльворт

@Oli: Це дійсно так. Я додав його до дрібного шрифту, оскільки, на мою думку, це не є загальним і достатньо важливим, щоб бути зазначеним у головному тексті.
sbi

3
Для повноти, можливо, варто зазначити, що operator*()також можна перевантажувати, і що ніщо не змушує цього перевантаження узгоджуватись operator->()! (Я не спростовував BTW, просто потрапив сюди через довгу послідовність дублікатів)
juanchopanza

@OliCharlesworth Ви б знали, де це вказано в стандарті C ++?
свиня

1
@juanchopanza: Однак, ви не можете домогтися ланцюгової поведінки ->через перевантаження operator*та використання .. Тільки operator->перевантаження отримують це.
Бен Войгт

36

Пропоную альтернативу для пункту 3 sbi

a->bвикористовується лише якщо aє вказівник. Це скорочена (*a).b, то bчлен об'єкта , який aвказує. C ++ має два види покажчиків, "регулярні" та інтелектуальні. Для звичайних покажчиків, таких як A* a, компілятор реалізує ->. Для розумних покажчиків, таких як std::shared_ptr<A> a, ->є функція члена класу shared_ptr.

Обґрунтування: цільова аудиторія цього FAQ не пише розумні покажчики. Їм не потрібно знати ->, що насправді викликається operator->(), або що це єдиний метод доступу, який може бути перевантажений.


4
Незалежно від того, згоден я з цим, чи ні, я даю це +1лише для надання альтернативної відповіді.
sbi

2
Добре, справедливість ->також перевантажена стандартними ітераторами, з якими незабаром повинен зустрітись будь-який програміст на C ++, так що мовлення, яке використовується лише для покажчиків, може заплутати.
Kiscsirke

@Kiscsirke "звичайним програмістам на C ++" не потрібно писати інтелектуальні вказівники чи ітератор, просто використовуючи їх. "Відхилення як вказівник" стосується обох.
Калет

0
#include <iostream>
#include <string>

using namespace std;

class Human {
private:
    int age;

public:
    string name;

    Human(int humanAge, string humanName) 
         : age(humanAge), name(std::move(humanName)) {}

    void DoSomething() {
        cout << age << endl;
    }

    static void DisplayAge(const Human& person) {
        cout << person.age << endl;
    }

    // ...
};

int main() {
    // Usage of Dot(.) 
    Human firstMan(13, "Jim"); // firstMan is an instance of class Human
    cout << firstMan.name << endl; // accessing member attributes
    firstMan.DoSomething(); // accessing member functions

    // Usage of Pointer Operator (->)
    Human* secondMan = new Human(24, "Tom");
    cout << secondMan->name << endl; // accessing member attributes
    secondMan->DoSomething(); // accessing member functions
    cout << (*secondMan).name << endl; // accessing member attributes
    (*secondMan).DoSomething(); // accessing member functions

    // Usage of Double Colon (::)
    Human::DisplayAge(firstMan);
    firstMan.DisplayAge(firstMan); // ok but not recommended
    secondMan->DisplayAge(firstMan); // ok but not recommended

    delete(secondMan);

    return 0;
}

З наведеного вище прикладу кодування ми бачимо, що:
* Доступ до членів (атрибутів та функцій) з екземпляра (або об'єкта) за допомогою оператора крапок ( .)
* Доступ до членів (атрибутів та функцій) від вказівника до об'єкта (або створеного new) за допомогою оператора вказівника ( ->)
* Доступ до статичних функцій-членів із самого класу без об'єкта як ручки за допомогою подвійної двокрапки ( ::). [ Примітка: ви також можете викликати функцію статичного члена з екземпляра, з яким .або ->не рекомендується]


@sbi так бурхливо га, я знаю, що це якесь повторення. Я просто хочу навести явний приклад, щоб показати, як ними користуватися. І де я сказав, що ->може використовуватись лише вказівник, який виділив на купі new? Нижче, другий пункт, я думаю, я дійсно даю зрозуміти, що ->це для покажчика. І перед тим, як звернути увагу, краще спробуйте className::non_static_member_function()с ++ 14 самостійно. Посилання - не вказівник, тому воно може використовуватись ., і я зроблю це більш зрозумілим у своїй відповіді.
Ху Сісі

0

Оператор крапок використовується в сценаріях вибору прямих членів.

print(a.b)

Тут ми звертаємось b, який є безпосереднім членом об’єкта a. Отже, насамперед, aє об'єктом і bє членом (функцією / змінною тощо) a.


Оператор зі стрілками використовується в непрямих сценаріях вибору членів.

print(a->b)

Тут ми отримуємо доступ до того, bхто є об'єктом, на який вказує a. Це скорочення (*a).bі так тут, aв першу чергу, є вказівником на об'єкт і bє членом цього об'єкта.


Оператор Double Colon (Scope) використовується в сценаріях вибору прямого члена, пов'язаних з простором імен.

print(a::b)

Тут ми звертаємось до bчлена класу / простору імен a. Отже, насамперед, aце клас / простір імен і bє членом (функція / змінна тощо) a.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.