Создание классов и объектов в C++

C++C++Beginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом лабораторном занятии (lab) вы научитесь создавать классы и объекты в программировании на языке C++. Вы определите классы с приватными (private) данными-членами, реализуете публичные (public) методы-члены, создадите конструкторы с разными параметрами, напишете деструкторы для очистки ресурсов, используете спецификаторы доступа, реализуете наследование между классами, переопределите методы базового класса, создадите дружественные (friend) функции для контроля доступа и используете статические (static) члены и методы. Эти концепции являются фундаментальными для объектно-ориентированного программирования на C++ и предоставят прочный фундамент для создания более сложных приложений.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL cpp(("C++")) -.-> cpp/FunctionsGroup(["Functions"]) cpp(("C++")) -.-> cpp/OOPGroup(["OOP"]) cpp(("C++")) -.-> cpp/BasicsGroup(["Basics"]) cpp/BasicsGroup -.-> cpp/data_types("Data Types") cpp/FunctionsGroup -.-> cpp/function_parameters("Function Parameters") cpp/OOPGroup -.-> cpp/classes_objects("Classes/Objects") cpp/OOPGroup -.-> cpp/class_methods("Class Methods") cpp/OOPGroup -.-> cpp/access_specifiers("Access Specifiers") cpp/OOPGroup -.-> cpp/constructors("Constructors") cpp/OOPGroup -.-> cpp/encapsulation("Encapsulation") cpp/OOPGroup -.-> cpp/inheritance("Inheritance") cpp/OOPGroup -.-> cpp/polymorphism("Polymorphism") subgraph Lab Skills cpp/data_types -.-> lab-446079{{"Создание классов и объектов в C++"}} cpp/function_parameters -.-> lab-446079{{"Создание классов и объектов в C++"}} cpp/classes_objects -.-> lab-446079{{"Создание классов и объектов в C++"}} cpp/class_methods -.-> lab-446079{{"Создание классов и объектов в C++"}} cpp/access_specifiers -.-> lab-446079{{"Создание классов и объектов в C++"}} cpp/constructors -.-> lab-446079{{"Создание классов и объектов в C++"}} cpp/encapsulation -.-> lab-446079{{"Создание классов и объектов в C++"}} cpp/inheritance -.-> lab-446079{{"Создание классов и объектов в C++"}} cpp/polymorphism -.-> lab-446079{{"Создание классов и объектов в C++"}} end

Определение класса с приватными (private) данными-членами

Класс в C++ представляет собой шаблон для создания объектов. Он определяет набор свойств (данных-членов) и методов (функций-членов), которые будут у объектов, созданных на основе этого класса. Классы помогают организовать код и реализовать принципы объектно-ориентированного программирования, такие как инкапсуляция, наследование и полиморфизм.

Базовый синтаксис определения класса в C++ выглядит следующим образом:

class ClassName {
private:
    // Private data members
    int dataMember1;
    std::string dataMember2;

public:
    // Public member functions
    void memberFunction1();
    int memberFunction2();
};

В C++ есть три спецификатора доступа, которые контролируют видимость и доступность членов класса:

  • private: Члены, объявленные как private, доступны только внутри класса.
  • public: Члены, объявленные как public, доступны извне класса.
  • protected: Члены, объявленные как protected, доступны внутри класса и экземплярами производных классов.

На этом этапе вы научитесь определять класс с приватными данными-членами в C++. Приватные данные-члены - это важная концепция объектно-ориентированного программирования, которая помогает инкапсулировать и защитить внутреннее состояние объекта.

Сначала откройте WebIDE и перейдите в каталог ~/project. Создайте новый файл с именем student.cpp:

touch ~/project/student.cpp

Откройте файл student.cpp в WebIDE и добавьте следующий код для определения класса Student с приватными данными-членами:

#include <iostream>
#include <string>

class Student {
private:
    // Private data members
    std::string name;
    int age;
    double gpa;

public:
    // We'll add methods to interact with these private members in later steps
    void displayInfo() {
        std::cout << "Name: " << name << std::endl;
        std::cout << "Age: " << age << std::endl;
        std::cout << "GPA: " << gpa << std::endl;
    }
};

int main() {
    Student student;
    // Note: We can't directly access private members
    // student.name = "John"; // This would cause a compilation error

    student.displayInfo();
    return 0;
}

Разберем основные концепции:

  1. Приватные данные-члены:

    • Объявляются с использованием спецификатора доступа private:
    • Не могут быть напрямую доступны извне класса
    • Предоставляют защиту данных и инкапсуляцию
  2. Типы данных:

    • std::string name: Хранит имя студента
    • int age: Хранит возраст студента
    • double gpa: Хранит средний балл студента
  3. Инкапсуляция:

    • Приватные члены могут быть доступны только через публичные методы
    • Предотвращает прямое изменение внутренних данных

Скомпилируйте программу:

g++ student.cpp -o student
./student

Пример вывода при запуске программы:

Name:
Age: 0
GPA: 0

Основные моменты:

  • Приватные члены скрыты от внешнего доступа
  • Они могут быть изменены только через методы класса
  • Это помогает сохранить целостность и контроль данных

Реализация публичных (public) методов-членов

На этом этапе вы научитесь реализовывать публичные методы-члены в C++. Публичные методы-члены позволяют контролировать доступ к приватным (private) данным-членам и предоставляют способы взаимодействия с объектами класса.

Откройте файл student.cpp в WebIDE и измените класс Student, добавив в него публичные методы-члены:

#include <iostream>
#include <string>

class Student {
private:
    std::string name;
    int age;
    double gpa;

public:
    // Setter methods to modify private data members
    void setName(std::string studentName) {
        name = studentName;
    }

    void setAge(int studentAge) {
        if (studentAge > 0 && studentAge < 120) {
            age = studentAge;
        } else {
            std::cout << "Invalid age!" << std::endl;
        }
    }

    void setGPA(double studentGPA) {
        if (studentGPA >= 0.0 && studentGPA <= 4.0) {
            gpa = studentGPA;
        } else {
            std::cout << "Invalid GPA!" << std::endl;
        }
    }

    // Getter methods to access private data members
    std::string getName() {
        return name;
    }

    int getAge() {
        return age;
    }

    double getGPA() {
        return gpa;
    }

    // Display method to print student information
    void displayInfo() {
        std::cout << "Student Information:" << std::endl;
        std::cout << "Name: " << name << std::endl;
        std::cout << "Age: " << age << std::endl;
        std::cout << "GPA: " << gpa << std::endl;
    }
};

int main() {
    Student student;

    // Using public member functions to set and get data
    student.setName("Alice Johnson");
    student.setAge(20);
    student.setGPA(3.75);

    // Display student information
    student.displayInfo();

    // Demonstrate getter methods
    std::cout << "\nStudent Name: " << student.getName() << std::endl;
    std::cout << "Student Age: " << student.getAge() << std::endl;
    std::cout << "Student GPA: " << student.getGPA() << std::endl;

    return 0;
}

Скомпилируйте и запустите программу:

g++ student.cpp -o student
./student

Пример вывода:

Student Information:
Name: Alice Johnson
Age: 20
GPA: 3.75

Student Name: Alice Johnson
Student Age: 20
Student GPA: 3.75

Основные моменты о публичных методах-членах:

  • Предоставляют контролируемый доступ к приватным данным-членам
  • Методы-сеттеры (setters) позволяют изменять данные с валидацией
  • Методы-геттеры (getters) позволяют читать приватные данные
  • Помогают сохранить инкапсуляцию и целостность данных

Создание конструкторов с разными параметрами

На этом этапе вы научитесь создавать конструкторы с разными параметрами в C++. Конструкторы - это специальные методы-члены, которые инициализируют объекты при их создании.

Откройте файл student.cpp в WebIDE и измените класс Student, добавив в него несколько конструкторов:

#include <iostream>
#include <string>

class Student {
private:
    std::string name;
    int age;
    double gpa;

public:
    // Default constructor
    Student() {
        name = "Unknown";
        age = 0;
        gpa = 0.0;
    }

    // Constructor with name parameter
    Student(std::string studentName) {
        name = studentName;
        age = 0;
        gpa = 0.0;
    }

    // Constructor with name and age parameters
    Student(std::string studentName, int studentAge) {
        name = studentName;
        age = studentAge;
        gpa = 0.0;
    }

    // Full constructor with all parameters
    Student(std::string studentName, int studentAge, double studentGPA) {
        name = studentName;
        age = studentAge;
        gpa = studentGPA;
    }

    // Display method to print student information
    void displayInfo() {
        std::cout << "Student Information:" << std::endl;
        std::cout << "Name: " << name << std::endl;
        std::cout << "Age: " << age << std::endl;
        std::cout << "GPA: " << gpa << std::endl;
    }
};

int main() {
    // Using different constructors
    Student student1;  // Default constructor
    Student student2("Alice Johnson");  // Constructor with name
    Student student3("Bob Smith", 22);  // Constructor with name and age
    Student student4("Charlie Brown", 20, 3.75);  // Full constructor

    std::cout << "Student 1:" << std::endl;
    student1.displayInfo();

    std::cout << "\nStudent 2:" << std::endl;
    student2.displayInfo();

    std::cout << "\nStudent 3:" << std::endl;
    student3.displayInfo();

    std::cout << "\nStudent 4:" << std::endl;
    student4.displayInfo();

    return 0;
}

Скомпилируйте и запустите программу:

g++ student.cpp -o student
./student

Пример вывода:

Student 1:
Student Information:
Name: Unknown
Age: 0
GPA: 0

Student 2:
Student Information:
Name: Alice Johnson
Age: 0
GPA: 0

Student 3:
Student Information:
Name: Bob Smith
Age: 22
GPA: 0

Student 4:
Student Information:
Name: Charlie Brown
Age: 20
GPA: 3.75

Основные моменты о конструкторах:

  • Конструкторы имеют то же имя, что и класс
  • Они инициализируют данные-члены объекта
  • Может быть несколько конструкторов с разными параметрами
  • Вызываются автоматически при создании объекта

Написание деструктора для очистки ресурсов

На этом этапе вы узнаете о деструкторах в C++, которые представляют собой специальные методы-члены, ответственные за очистку ресурсов при уничтожении объекта. Мы покажем, как написать деструктор и поймем его важность в управлении памятью.

Откройте файл student.cpp в WebIDE и измените код, добавив деструктор и динамическое выделение памяти:

#include <iostream>
#include <string>

class Student {
private:
    std::string name;
    int age;
    double gpa;
    char* dynamicBuffer;  // Simulating dynamic memory allocation

public:
    // Constructors
    Student() {
        name = "Unknown";
        age = 0;
        gpa = 0.0;
        dynamicBuffer = new char[50];  // Allocate dynamic memory
        std::cout << "Default Constructor Called" << std::endl;
    }

    Student(std::string studentName) : name(studentName), age(0), gpa(0.0) {
        dynamicBuffer = new char[50];
        std::cout << "Parameterized Constructor Called" << std::endl;
    }

    // Destructor
    ~Student() {
        // Clean up dynamically allocated memory
        delete[] dynamicBuffer;
        std::cout << "Destructor Called for " << name << std::endl;
    }

    void displayInfo() {
        std::cout << "Student Information:" << std::endl;
        std::cout << "Name: " << name << std::endl;
        std::cout << "Age: " << age << std::endl;
        std::cout << "GPA: " << gpa << std::endl;
    }
};

int main() {
    // Demonstrating object creation and destruction
    {
        std::cout << "Creating first student:" << std::endl;
        Student student1("Alice Johnson");
        student1.displayInfo();

        std::cout << "\nCreating second student:" << std::endl;
        Student student2("Bob Smith");
        student2.displayInfo();
    }  // Objects go out of scope here, destructors are called

    std::cout << "\nExiting main function" << std::endl;
    return 0;
}

Скомпилируйте и запустите программу:

g++ student.cpp -o student
./student

Пример вывода:

Creating first student:
Parameterized Constructor Called
Student Information:
Name: Alice Johnson
Age: 0
GPA: 0

Creating second student:
Parameterized Constructor Called
Student Information:
Name: Bob Smith
Age: 0
GPA: 0

Destructor Called for Bob Smith
Destructor Called for Alice Johnson

Exiting main function

Основные моменты о деструкторах:

  • Определяются с использованием символа ~, за которым следует имя класса
  • Вызываются автоматически при уничтожении объекта
  • Используются для освобождения динамически выделенных ресурсов
  • Помогают предотвратить утечки памяти
  • Не имеют возвращаемого типа и параметров

Важные характеристики деструкторов:

  • Вызываются, когда объект выходит из области видимости
  • Автоматически вызываются компилятором
  • Ключевые для очистки динамической памяти
  • Помогают эффективно управлять системными ресурсами

Использование спецификаторов доступа (public, private, protected)

На этом этапе вы узнаете о спецификаторах доступа в C++ и о том, как они контролируют видимость и доступность членов класса. Мы рассмотрим различия между уровнями доступа public, private и protected.

Откройте файл student.cpp в WebIDE и измените код, чтобы продемонстрировать использование спецификаторов доступа:

#include <iostream>
#include <string>

class Student {
private:
    // Private members: accessible only within the class
    std::string name;
    int age;
    double gpa;

protected:
    // Protected members: accessible within the class and its derived classes
    std::string school;

public:
    // Public members: accessible from anywhere
    Student(std::string studentName, int studentAge, double studentGPA) {
        name = studentName;
        age = studentAge;
        gpa = studentGPA;
        school = "Default School";
    }

    // Public method to demonstrate access to private members
    void displayInfo() {
        std::cout << "Student Information:" << std::endl;
        std::cout << "Name: " << name << std::endl;  // Accessing private member
        std::cout << "Age: " << age << std::endl;
        std::cout << "GPA: " << gpa << std::endl;
        std::cout << "School: " << school << std::endl;
    }

    // Public method to modify private members
    void updateGPA(double newGPA) {
        if (newGPA >= 0.0 && newGPA <= 4.0) {
            gpa = newGPA;
        }
    }
};

class GraduateStudent : public Student {
public:
    GraduateStudent(std::string name, int age, double gpa)
        : Student(name, age, gpa) {
        // Can access protected 'school' member from base class
        school = "Graduate School";
    }

    void displaySchool() {
        std::cout << "School: " << school << std::endl;
    }
};

int main() {
    Student student("Alice Johnson", 20, 3.75);
    student.displayInfo();  // Public method accessing private members

    // Uncommenting the lines below would cause compilation errors
    // student.name = "John";  // Error: Cannot access private member
    // student.age = 25;       // Error: Cannot access private member

    student.updateGPA(3.90);  // Modifying private member through public method
    student.displayInfo();

    GraduateStudent gradStudent("Bob Smith", 25, 3.90);
    gradStudent.displayInfo();
    gradStudent.displaySchool();

    return 0;
}

Скомпилируйте и запустите программу:

g++ student.cpp -o student
./student

Пример вывода:

Student Information:
Name: Alice Johnson
Age: 20
GPA: 3.75
School: Default School
Student Information:
Name: Alice Johnson
Age: 20
GPA: 3.90
School: Default School
Student Information:
Name: Bob Smith
Age: 25
GPA: 3.90
School: Graduate School
School: Graduate School

Основные моменты о спецификаторах доступа:

  • private: Члены доступны только внутри того же класса
  • protected: Члены доступны внутри класса и его производных классов
  • public: Члены доступны из любого места
  • Помогают контролировать доступ к данным и сохранять инкапсуляцию

Реализация наследования между классами

На этом этапе вы узнаете о наследовании в C++, фундаментальном концепте объектно-ориентированного программирования, которое позволяет создавать новые классы на основе существующих.

Откройте файл student.cpp в WebIDE и измените код, чтобы продемонстрировать наследование:

#include <iostream>
#include <string>

// Base class
class Person {
protected:
    std::string name;
    int age;

public:
    // Constructor
    Person(std::string personName, int personAge) {
        name = personName;
        age = personAge;
    }

    // Method to display basic information
    void displayInfo() {
        std::cout << "Name: " << name << std::endl;
        std::cout << "Age: " << age << std::endl;
    }
};

// Derived class: Student inherits from Person
class Student : public Person {
private:
    double gpa;
    std::string major;

public:
    // Constructor that calls base class constructor
    Student(std::string studentName, int studentAge, double studentGPA, std::string studentMajor)
        : Person(studentName, studentAge) {
        gpa = studentGPA;
        major = studentMajor;
    }

    // Additional method specific to Student
    void displayStudentInfo() {
        // Calling base class method
        displayInfo();
        std::cout << "GPA: " << gpa << std::endl;
        std::cout << "Major: " << major << std::endl;
    }
};

// Another derived class: Employee inherits from Person
class Employee : public Person {
private:
    std::string company;
    double salary;

public:
    // Constructor that calls base class constructor
    Employee(std::string employeeName, int employeeAge, std::string employeeCompany, double employeeSalary)
        : Person(employeeName, employeeAge) {
        company = employeeCompany;
        salary = employeeSalary;
    }

    // Additional method specific to Employee
    void displayEmployeeInfo() {
        // Calling base class method
        displayInfo();
        std::cout << "Company: " << company << std::endl;
        std::cout << "Salary: $" << salary << std::endl;
    }
};

int main() {
    // Creating objects of derived classes
    Student student("Alice Johnson", 20, 3.75, "Computer Science");
    std::cout << "Student Information:" << std::endl;
    student.displayStudentInfo();

    std::cout << "\n";

    Employee employee("Bob Smith", 35, "Tech Corp", 75000.0);
    std::cout << "Employee Information:" << std::endl;
    employee.displayEmployeeInfo();

    return 0;
}

Скомпилируйте и запустите программу:

g++ student.cpp -o student
./student

Пример вывода:

Student Information:
Name: Alice Johnson
Age: 20
GPA: 3.75
Major: Computer Science

Employee Information:
Name: Bob Smith
Age: 35
Company: Tech Corp
Salary: $75000

Основные моменты о наследовании:

  • Базовый класс (Person) содержит общие атрибуты
  • Производные классы (Student, Employee) наследуются от базового класса
  • Используйте : public BaseClassName для наследования
  • Можно добавлять новые атрибуты и методы в производных классах
  • Можно использовать методы базового класса в производных классах

Переопределение методов базового класса

На этом этапе вы узнаете, как переопределять методы базового класса в C++, что позволяет производным классам предоставлять свою собственную реализацию методов, унаследованных от базового класса.

Откройте файл student.cpp в WebIDE и измените код, чтобы продемонстрировать переопределение методов:

#include <iostream>
#include <string>

class Animal {
protected:
    std::string name;

public:
    Animal(std::string animalName) : name(animalName) {}

    // Virtual keyword allows method to be overridden
    virtual void makeSound() {
        std::cout << "Some generic animal sound" << std::endl;
    }

    // Virtual method for displaying information
    virtual void displayInfo() {
        std::cout << "Animal Name: " << name << std::endl;
    }
};

class Dog : public Animal {
private:
    std::string breed;

public:
    Dog(std::string dogName, std::string dogBreed)
        : Animal(dogName), breed(dogBreed) {}

    // Override makeSound method
    void makeSound() override {
        std::cout << "Woof! Woof!" << std::endl;
    }

    // Override displayInfo method
    void displayInfo() override {
        // Call base class method first
        Animal::displayInfo();
        std::cout << "Breed: " << breed << std::endl;
    }
};

class Cat : public Animal {
private:
    std::string color;

public:
    Cat(std::string catName, std::string catColor)
        : Animal(catName), color(catColor) {}

    // Override makeSound method
    void makeSound() override {
        std::cout << "Meow! Meow!" << std::endl;
    }

    // Override displayInfo method
    void displayInfo() override {
        // Call base class method first
        Animal::displayInfo();
        std::cout << "Color: " << color << std::endl;
    }
};

int main() {
    // Create animal objects
    Animal genericAnimal("Generic Animal");
    Dog myDog("Buddy", "Labrador");
    Cat myCat("Whiskers", "Orange");

    // Demonstrate polymorphic behavior
    std::cout << "Generic Animal:" << std::endl;
    genericAnimal.displayInfo();
    genericAnimal.makeSound();

    std::cout << "\nDog:" << std::endl;
    myDog.displayInfo();
    myDog.makeSound();

    std::cout << "\nCat:" << std::endl;
    myCat.displayInfo();
    myCat.makeSound();

    return 0;
}

Скомпилируйте и запустите программу:

g++ student.cpp -o student
./student

Пример вывода:

Generic Animal:
Animal Name: Generic Animal
Some generic animal sound

Dog:
Animal Name: Buddy
Breed: Labrador
Woof! Woof!

Cat:
Animal Name: Whiskers
Color: Orange
Meow! Meow!

Основные моменты о переопределении методов:

  • Используйте ключевое слово virtual в базовом классе, чтобы разрешить переопределение
  • Используйте ключевое слово override в производном классе, чтобы явно переопределить метод
  • Можно вызвать метод базового класса с помощью BaseClass::method()
  • Позволяет иметь разные реализации для одного и того же метода
  • Обеспечивает полиморфное поведение

Создание дружественных функций для контроля доступа

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

Откройте файл student.cpp в WebIDE и измените код, чтобы продемонстрировать использование дружественных функций:

#include <iostream>
#include <string>

class BankAccount {
private:
    std::string accountHolder;
    double balance;

    // Declare friend functions
    friend void displayAccountDetails(const BankAccount& account);
    friend class AccountManager;

public:
    // Constructor
    BankAccount(std::string name, double initialBalance) {
        accountHolder = name;
        balance = initialBalance;
    }

    // Method to deposit money
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }
};

// Friend function that can access private members
void displayAccountDetails(const BankAccount& account) {
    std::cout << "Account Holder: " << account.accountHolder << std::endl;
    std::cout << "Current Balance: $" << account.balance << std::endl;
}

// Friend class that can access private members
class AccountManager {
public:
    // Method that can access private members of BankAccount
    void transferFunds(BankAccount& from, BankAccount& to, double amount) {
        if (from.balance >= amount) {
            from.balance -= amount;
            to.balance += amount;
            std::cout << "Transfer successful!" << std::endl;
        } else {
            std::cout << "Insufficient funds!" << std::endl;
        }
    }
};

int main() {
    // Create bank accounts
    BankAccount account1("Alice Johnson", 1000.0);
    BankAccount account2("Bob Smith", 500.0);

    // Use friend function to display account details
    std::cout << "Account 1 Details:" << std::endl;
    displayAccountDetails(account1);

    std::cout << "\nAccount 2 Details:" << std::endl;
    displayAccountDetails(account2);

    // Use friend class to transfer funds
    AccountManager manager;
    std::cout << "\nTransferring $200 from Alice to Bob:" << std::endl;
    manager.transferFunds(account1, account2, 200.0);

    std::cout << "\nUpdated Account Details:" << std::endl;
    displayAccountDetails(account1);
    displayAccountDetails(account2);

    return 0;
}

Скомпилируйте и запустите программу:

g++ student.cpp -o student
./student

Пример вывода:

Account 1 Details:
Account Holder: Alice Johnson
Current Balance: $1000

Account 2 Details:
Account Holder: Bob Smith
Current Balance: $500

Transferring $200 from Alice to Bob:
Transfer successful!

Updated Account Details:
Account Holder: Alice Johnson
Current Balance: $800
Account Holder: Bob Smith
Current Balance: $700

Основные моменты о дружественных функциях:

  • Объявляются с использованием ключевого слова friend
  • Можно получить доступ к приватным и защищенным членам класса
  • Объявляются внутри определения класса
  • Может быть отдельной функцией или целым классом
  • Нарушает инкапсуляцию, поэтому используйте с осторожностью

Использование статических членов и методов

На этом этапе вы узнаете о статических членах и методах в C++, которые являются общими для всех экземпляров класса и принадлежат самому классу, а не отдельным объектам.

Откройте файл student.cpp в WebIDE и измените код, чтобы продемонстрировать использование статических членов и методов:

#include <iostream>
#include <string>

class University {
private:
    std::string name;
    static int totalStudents;  // Static member variable
    static double totalTuition;  // Another static member variable

public:
    // Constructor
    University(std::string universityName) : name(universityName) {}

    // Method to add students
    void addStudents(int count) {
        totalStudents += count;
    }

    // Method to add tuition
    void addTuition(double amount) {
        totalTuition += amount;
    }

    // Static method to display total students
    static void displayTotalStudents() {
        std::cout << "Total Students Across All Universities: "
                  << totalStudents << std::endl;
    }

    // Static method to display total tuition
    static void displayTotalTuition() {
        std::cout << "Total Tuition Collected: $"
                  << totalTuition << std::endl;
    }

    // Static method to calculate average tuition
    static double calculateAverageTuition() {
        return (totalStudents > 0)?
               (totalTuition / totalStudents) : 0.0;
    }
};

// Initialize static member variables outside the class
int University::totalStudents = 0;
double University::totalTuition = 0.0;

int main() {
    // Create university objects
    University harvard("Harvard University");
    University mit("MIT");
    University stanford("Stanford University");

    // Add students and tuition
    harvard.addStudents(5000);
    harvard.addTuition(75000000.0);

    mit.addStudents(4500);
    mit.addTuition(65000000.0);

    stanford.addStudents(4200);
    stanford.addTuition(60000000.0);

    // Call static methods directly on the class
    std::cout << "University Statistics:" << std::endl;
    University::displayTotalStudents();
    University::displayTotalTuition();

    // Calculate and display average tuition
    std::cout << "Average Tuition per Student: $"
              << University::calculateAverageTuition() << std::endl;

    return 0;
}

Скомпилируйте и запустите программу:

g++ student.cpp -o student
./student

Пример вывода:

University Statistics:
Total Students Across All Universities: 13700
Total Tuition Collected: $2e+08
Average Tuition per Student: $14598.5

Основные моменты о статических членах и методах:

  • Общие для всех экземпляров класса
  • Объявляются с использованием ключевого слова static
  • Можно обращаться к ним без создания объекта
  • Принадлежат классу, а не отдельным объектам
  • Полезны для отслеживания информации, относящейся ко всему классу

Итог

В этом практическом занятии вы научились определять класс с приватными членами данных, что является важной концепцией в объектно-ориентированном программировании. Приватные члены данных помогают инкапсулировать и защитить внутреннее состояние объекта. Вы также узнали о важности публичных методов-членов, которые позволяют контролировать доступ к приватным членам данных. Это помогает сохранить целостность и контроль данных. Кроме того, вы изучили использование конструкторов, деструкторов, спецификаторов доступа, наследования, переопределения методов, дружественных функций, а также статических членов и методов, все это - фундаментальные принципы объектно-ориентированного программирования в C++.