1 Востаннє редагувалося mamkin haker (22.08.2021 10:06:46)

Тема: виклик функції без оголошення обєкта класу в якому вона розміщена

Доброго дня ^^
перепрошую за дуже тупе запитання але чи можна якось визвати публічну функцію з класу і щоб при цьому не створювати обєкт цього класу

//C++
#include "User.h"
#include "User_buying.h"
#include "User_change_name.h"

int main() {
    User admin;
    User_buying user_buying; // ось тут не створювати
    User_change_name user_change_name; //та тут

    admin = user_buying.buying(admin, 300);
    admin = user_buying.buying(admin, 900);

    admin = user_change_name.change_name(admin, "admin");
    admin = user_change_name.change_name(admin, "");

    printf("%s\n%f\n\n", admin.get_name(), admin.get_money());
}

наприклад як на пайтон

#Python

class Class():
    x = 1

print(Class.x) //1
повний код, якщо необхідно

main.cc

#include "User.h"
#include "User_buying.h"
#include "User_change_name.h"

int main() {
    User admin;
    User_buying user_buying;
    User_change_name user_change_name;

    admin = user_buying.buying(admin, 300);
    admin = user_buying.buying(admin, 900);

    admin = user_change_name.change_name(admin, "admin");
    admin = user_change_name.change_name(admin, "");

    printf("%s\n%f\n\n", admin.get_name(), admin.get_money());
}

User.h

class User {
    //money
    public: void money_update(float money) {
        this -> money = money;
    }
    
    public: float get_money() { 
        return this -> money;
    }

    //name
    public: void name_update(const char* name) {
        this -> name = name;
    }

    public: const char* get_name() {
        return this -> name;
    }

    //variable
    private: const char* name = "user";
    private: float money = 1000;
};

User_change_name.h

#include <iostream>

class User_change_name {
    public: User change_name(User user, const char* name) {
        if (check_name(name)){
            user.name_update(name);
            printf("і'мя змінено\n");
        }
        else {
            printf("Невдача\n");
        }

        return user;
    }

    private: bool check_name(const char* name) {
        for (int i = 0; i < len_banned_names; i++){
            if (banned_names[i] == name) {
                return false;
            }
        }

        return true;
    }

    private: const char* banned_names[1] = {""};
    private: int len_banned_names = sizeof(banned_names)/sizeof(banned_names[0]);
};

User_buying.h

#include <iostream>

class User_buying {
    public: User buying(User user, float price) {
        if (price < user.get_money()) {
            user.money_update(user.get_money() - price);
            printf("Покупка виконана!");
        }
        else {
            printf("Недостатньо коштів\n");
        }
        
        return user;
    }
};

2 Востаннє редагувалося ch0r_t (22.08.2021 10:21:21)

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

"Static Function Members" - Це те чого ви хочете?

By declaring a function member as static, you make it independent of any particular object of the class. A static member function can be called even if no objects of the class exist and the static functions are accessed using only the class name and the scope resolution operator ::.

Тут приклад -> https://pencilprogrammer.com/cpp-tutori … cplusplus/
https://www.tutorialspoint.com/cplusplu … embers.htm

А по якому це ви підручнику вивчаєте хрести з півмісяцем, дозвольте запитати?

Подякували: koala1

3 Востаннє редагувалося mamkin haker (22.08.2021 10:41:07)

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

я це вже знаходив
tchort дякую, непомітив що там є static :D
проморгав це слово XD
я дурак

#include <iostream>
class User{
    public: static void foo();
};

void User::foo(){
    printf("Обєкт не створений а функція визвана\n");
}

int main(){
    User::foo();
}

4 Востаннє редагувалося koala (22.08.2021 10:31:16)

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

mamkin haker написав:

там оголошуєтся перемінна пред int main(){}

Так не проголошуйте ту змінну, в чому проблема?
Ну і вам чітко написали: вам потрібна статична функція. Тобто проголошена зі словом static. Де у вас у коді слово static?

5 Востаннє редагувалося mamkin haker (22.08.2021 10:45:12)

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

koala написав:
mamkin haker написав:

там оголошуєтся перемінна пред int main(){}

Так не проголошуйте ту змінну, в чому проблема?
Ну і вам чітко написали: вам потрібна статична функція. Тобто проголошена зі словом static. Де у вас у коді слово static?

дякую, уже помітив, я прост сліпий, бачення -1448 (жарт)

ехх обійдусь без перевірки імені :D

#include <iostream>

class User_change_name {
    public: static User change_name(User user, const char* name) {
        if (check_name(name)){
            user.name_update(name);
            printf("і'мя змінено\n");
        }
        else {
            printf("Невдача\n");
        }

        return user;
    }

    private: static bool check_name(const char* name) {
        for (int i = 0; i < len_banned_names; i++){
            if (banned_names[i] == name) {
                return false;
            }
        }

        return true;
    }

    private: static const char* banned_names[1] = {""}; //нізя
    private: static int len_banned_names = sizeof(banned_names)/sizeof(banned_names[0]); //нізя
};

6 Востаннє редагувалося koala (22.08.2021 10:42:11)

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

Коли допишете код, викладете його сюди на рев'ю, добре? Я маю тут кілька суттєвих зауважень, але очевидно, що ви ще активно його змінюєте, можливо, коли доредагуєте, вони вже не матимуть сенсу.

7

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

koala написав:

Коли допишете код, викладете його сюди на рев'ю, добре? Я маю тут кілька суттєвих зауважень, але очевидно, що ви ще активно його змінюєте, можливо, коли доредагуєте, вони вже не матимуть сенсу.

ось =(
вибирайте як вам зручніше

все в 1 кучу скидав
#include <iostream>

class User {
    //money
    public: void money_update(float money) {
        this -> money = money;
    }
    
    public: float get_money() { 
        return this -> money;
    }

    //name
    public: void name_update(const char* name) {
        this -> name = name;
    }

    public: const char* get_name() {
        return this -> name;
    }

    //variable
    private: const char* name = "user";
    private: float money = 1000;
};


class User_buying {
    public: static User buying(User user, float price) {
        if (price < user.get_money()) {
            user.money_update(user.get_money() - price);
            printf("Покупка виконана!\n");
        }
        else {
            printf("Недостатньо коштів\n");
        }
        
        return user;
    }
};


class User_change_name {
    public: static User change_name(User user, const char* name) {
        if (name != ""){
            user.name_update(name);
            printf("і'мя змінено\n");
        }
        else {
            printf("Невдача\n");
        }

        return user;
    }
};


int main() {
    User admin;

    admin = User_buying::buying(admin, 300);
    admin = User_buying::buying(admin, 900);

    admin = User_change_name::change_name(admin, "admin");
    admin = User_change_name::change_name(admin, "");

    printf("%s\n%f\n\n", admin.get_name(), admin.get_money());
}
розділено по блокам (кожен блок під своїм спойлером)
main.cc
#include "User.h"
#include "User_buying.h"
#include "User_change_name.h"

int main() {
    User admin;

    admin = User_buying::buying(admin, 300);
    admin = User_buying::buying(admin, 900);

    admin = User_change_name::change_name(admin, "admin");
    admin = User_change_name::change_name(admin, "");

    printf("%s\n%f\n\n", admin.get_name(), admin.get_money());
}
User.h
class User {
    //money
    public: void money_update(float money) {
        this -> money = money;
    }
    
    public: float get_money() { 
        return this -> money;
    }

    //name
    public: void name_update(const char* name) {
        this -> name = name;
    }

    public: const char* get_name() {
        return this -> name;
    }

    //variable
    private: const char* name = "user";
    private: float money = 1000;
};
User_buying.h
#include <iostream>

class User_buying {
    public: static User buying(User user, float price) {
        if (price < user.get_money()) {
            user.money_update(user.get_money() - price);
            printf("Покупка виконана!\n");
        }
        else {
            printf("Недостатньо коштів\n");
        }
        
        return user;
    }
};
User_change_name.h
#include <iostream>

class User_change_name {
    public: static User change_name(User user, const char* name) {
        if (name != "") {
            user.name_update(name);
            printf("і'мя змінено\n");
        }
        else {
            printf("Невдача\n");
        }

        return user;
    }
};

8 Востаннє редагувалося koala (22.08.2021 11:28:33)

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

Ви з Java на C++ переходите, судячи з public: в один рядок із членом класу?

1. const char * - це вказівник, і if (name != "") буде порівнювати вказівник на name із вказівником на "". Які можуть виявитися як однаковими, так і різними при однакових вмістах стрічок (""). Стрічки треба порівнювати функцією strcmp.
2. Клас user не володіє даними імені. Тобто код

std::string new_name {"abc"};
user.name_update(new_name.c_str());
new_name[1] = "d";
std::cout<<user.get_name(); //UB - звернення до казна-чого в пам'яті. У цьому місці, швидше за все, ім'я юзера буде adc
new_name = "sdiofhweiuhsoifhoshflsdhflskdhfsdlhfslhfsdl";
std::cout<<user.get_name(); //а тут вже усе що завгодно може статися, аж до падіння

Зберігайте гроші в банку стрічки в std::string. Це, до речі, розв'яже проблему з порівнянням.
3. Є різні концепції роботи з даними; в одній з них об'єкти незмінні, а функції створюють і повертають нові об'єкти, а в іншій - функції змінюють об'єкти. Загалом, свої переваги є в обох, але якщо об'єкт незмінний - то й не змінюйте його, а якщо змінний - то не перевантажуйте код перестворенням і перезаписуванням того, що ви змінюєте. Якось визначайтеся. const User& вам у поміч.
4. Користувачу ви повідомляєте, чи відбулася операція; але код далі цього не знає. Якось треба це вирішити.
5. Іменування в стилі Перша_велика_через_підкреслення вважається поганим. Обирайте - або маленькі_через_підкреслення, або КожнеСловоЗВеликоїБезПідкреслень. Для типів частіше використовується друге.
6. Змінні-члени класу бажано якось позначати, скажімо, не name, а name_ чи m_name.
7. Функція printf знаходиться не в <iostream>, а в <cstdio>. Але якщо ви вже вчите C++, а не C - краще використовуйте std::cout.

Подякували: leofun011

9

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

0) джаву бачив коли в майнкрафт грав :D (а те що паблік в 1 стрічку це напевно від того що С++ по відео урокам C# вчив :D)
1) незнав, дякую, виправлю і запамятаю
2) зрозуміло, тобто про char можна забути :D? (це мені ще клас Bank створювати?)

доповнення до 2

пямятаю мені хтось сказав що в ооп щоб створити банан потрібно ще створити мавпу і пальму на якій банан росте

5) а можна класи називати ось так UserBuying а перемінні та функції так get_name ?
6) protected: std::string _name; private: std::string __name; згодиться? (так в пайтоні функції протектед та пріват позначаються)
7) зрозумів, буду використовувати std::cout; у вікіпедії щось читав таке що код з С максимально намагались "впихнути" в С++, щоб полегшити перехід з С на С++

з іншим пізніше розберусь :D

10

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

2) Ні, іноді їх теж доводиться використовувати, особливо коли інші бібліотеки з ними працюють. Просто треба пам'ятати, що char * - це вказівник на чужі дані, і не можна покладатися на те, що ці дані залишаться незмінними. Тобто приймати його у функцію - нормально, а от зберігати для подальшого використання (без певних засторог) - ні.

    void name_update(const char* name) {
        this -> name_ = name; //це працює
    }

    const std::string& get_name() const { //а тут міняємо тип, що метод повертає
        return this -> name_;
    }

    std::string name_ { "user" }; //тепер дані зберігаються в об'єкті

5) Так, це загальноприйнята практика.
6) Правилам мови це не суперечить, але загальна практика - підкреслення на початку (особливо два підкреслення) зарезервовані для передвизначених макросів та ідентифікаторів, специфічних для компіляторів. Звісно, ймовірність потрапити в такий ідентифікатор низька, але нащо ризикувати?

11 Востаннє редагувалося wander (23.08.2021 21:13:29)

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

mamkin haker написав:
protected: std::string _name; private: std::string __name;
Прихований текст

Ще трішки вкину про підкреслення.

Rule of thumb: Don't use (double) underscores before any variable name or parameter name.

[lex.name]/3 написав:

In addition, some identifiers are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.
— Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
— Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace.

(p2, C++ Coding Standards, Herb Sutter and Andrei Alexandrescu) написав:

Don't overlegislate naming, but do use a consistent naming convention: There are only two must-dos: a) never use "underhanded names," ones that begin with an underscore or that contain a double underscore; and b) always use ONLY_UPPERCASE_NAMES for macros.

Якщо коротко: імена, що починаються з підкреслення або подвійного підкреслення, зарезервовані для реалізаторів C++. Імена з підкресленням також зарезервовані для std/experimental бібліотеки.
______________________________

mamkin haker написав:
class User_change_name {
    public: static User change_name(User user, const char* name) {
        if (name != ""){
            user.name_update(name);
            printf("і'мя змінено\n");
        }
        else {
            printf("Невдача\n");
        }

        return user;
    }
};

І нащо воно вам? С++ -- це не лише class орієнтована мова, написати вільну функцію ніхто не забороняє.

mamkin haker написав:
int main() {
    // ...
    // звучить, як Зміна_імені_користувача::зміна_імені
    // виходячи з оголошення функції і так зрозуміло, що вона змінить ім'я 
    // користувача, двічі про це говороти не потрібно :)
    admin = User_change_name::change_name(admin, "admin");
}

Достатньо просто:

int main() {
    // ...
    admin = change_name(admin, "admin");
}

12

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

Ну і коротко про те, що таке ООП.

13 Востаннє редагувалося mamkin haker (24.08.2021 14:45:31)

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

Переписав все з нуля :D
Ніби все нормально вже.
Ну це я так думаю =(

хоча можна в продукті дещо змінити
upd: змінив

що змінив

було

#pragma once

#include <iostream>
#include <string>
#include "User.h"

class Product
{
public:
    double price_;
    std::string name_;
    std::string manufacturer_;

    Product(){}

    double virtual get_price(User* user)
    {
        if (user -> spent_ < 1000)
        {
            return price_;
        }
        
        if (user -> spent_ < 5000)
        {
            return price_ * 0.9; 
        }
        
        return price_ * 0.8;
    }

    void virtual info()
    {
        std::cout << "Назва: "    << this -> name_         << "\n"
                  << "Ціна: "     << this -> price_        << "\n"
                  << "Виробник "  << this -> manufacturer_ << "\n";
    }
};

class Bread : public Product
{
public:
    Bread(double price, std::string name, std::string manufacturer)
    {
        this -> price_        = price;
        this -> name_         = name;
        this -> manufacturer_ = manufacturer;
    }
};

class Milk : public Product
{
public:
    double oiliness_;

    Milk(double price, std::string name, std::string manufacturer, double oiliness)
    {
        this -> price_        = price;
        this -> name_         = name;
        this -> manufacturer_ = manufacturer;
        this -> oiliness_     = oiliness;
    }

    double get_price(User* user) override
    {
        return price_ * 0.9;
    }

    void info() override
    {
        Product::info();
        std::cout << "Жирність: " << oiliness_ << "\n";
    }
};

class Gold : public Product
{
public:
    Gold(double price, std::string name, std::string manufacturer)
    {
        this -> price_        = price;
        this -> name_         = name;
        this -> manufacturer_ = manufacturer;
    }
};

стало

#pragma once

#include <iostream>
#include <string>
#include "User.h"

class Product
{
public:
    double price_;
    std::string name_;
    std::string manufacturer_;

    Product(double price, std::string name, std::string manufacturer)
    {
        this -> price_        = price;
        this -> name_         = name;
        this -> manufacturer_ = manufacturer;
    }

    double virtual get_price(User* user)
    {
        if (user -> spent_ < 1000)
        {
            return price_;
        }
        
        if (user -> spent_ < 5000)
        {
            return price_ * 0.9; 
        }
        
        return price_ * 0.8;
    }

    void virtual info()
    {
        std::cout << "Назва: "    << this -> name_         << "\n"
                  << "Ціна: "     << this -> price_        << "\n"
                  << "Виробник "  << this -> manufacturer_ << "\n";
    }
};

class Bread : public Product
{
public:
    Bread(double price, std::string name, std::string manufacturer):
    Product(price, name, manufacturer) {}
};

class Milk : public Product
{
public:
    double oiliness_;

    Milk(double price, std::string name, std::string manufacturer, double oiliness):
    Product(price, name, manufacturer)
    {
        this -> oiliness_ = oiliness;
    }

    double get_price(User* user) override
    {
        return price_ * 0.9;
    }

    void info() override
    {
        Product::info();
        std::cout << "Жирність: " << oiliness_ << "\n";
    }
};

class Gold : public Product
{
public:
    Gold(double price, std::string name, std::string manufacturer)
    :Product(price, name, manufacturer) {}

    double get_price(User* user) override
    {
        return price_;
    }
};

код
main.cc
#include <iostream>
#include <thread>

#include "User.h"
#include "Product.h"
#include "Informer.h"

int main()
{
    Informer informer;
    User* admin = new User("Київ, вул.Соборна 19", "admin", 10000);
    Product* products[3] = {
        new Bread(16, "хліб круглий", "хз"),
        new Milk(30, "молоко селянське", "Люстдорф", 2.5),
        new Gold(1000, "золото", "НБУ")
    };

    int num = 0;
    int size = sizeof(products)/sizeof(products[0]);

    while (true)
    {
        std::cout << "Вітаю!\nВаш баланс: " << admin -> balance_ << "\n\n";

        for (int i = 0; i < size; i++)
        {
            std::cout << "Номер товару " << i << "\n";
            products[i] -> info();
            std::cout << std::endl;
        }

        std::cout << "Введіть номер тавару та нажміть ентер\n";
        std::cin  >> num;

        if (!(std::cin))
        {
            break;
        }
        
        std::cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";

        if ((num >= 0) && (num < size))
        {
            informer.buy(admin, products[num]);
        }
        else
        {
            std::cout << "Таких товарів немає!\n";
            break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(3000));

        std::cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
    }
}
User.h
#pragma once
#include <iostream>

class User
{
public:
    std::string adress_;
    std::string name_;
    double balance_;
    double spent_;

    User(const char* adress, const char* name, double balance):
        adress_(adress),
        name_(name),
        balance_(balance),
        spent_(0)
        {}

    void reduce_balance(double price)
    {
        balance_ -= price;
        spent_    += price;
    }
};
Product.h
#pragma once

#include <iostream>
#include <string>
#include "User.h"

class Product
{
public:
    double price_;
    std::string name_;
    std::string manufacturer_;

    Product(double price, std::string name, std::string manufacturer)
    {
        this -> price_        = price;
        this -> name_         = name;
        this -> manufacturer_ = manufacturer;
    }

    double virtual get_price(User* user)
    {
        if (user -> spent_ < 1000)
        {
            return price_;
        }
        
        if (user -> spent_ < 5000)
        {
            return price_ * 0.9; 
        }
        
        return price_ * 0.8;
    }

    void virtual info()
    {
        std::cout << "Назва: "    << this -> name_         << "\n"
                  << "Ціна: "     << this -> price_        << "\n"
                  << "Виробник "  << this -> manufacturer_ << "\n";
    }
};

class Bread : public Product
{
public:
    Bread(double price, std::string name, std::string manufacturer):
    Product(price, name, manufacturer) {}
};

class Milk : public Product
{
public:
    double oiliness_;

    Milk(double price, std::string name, std::string manufacturer, double oiliness):
    Product(price, name, manufacturer)
    {
        this -> oiliness_ = oiliness;
    }

    double get_price(User* user) override
    {
        return price_ * 0.9;
    }

    void info() override
    {
        Product::info();
        std::cout << "Жирність: " << oiliness_ << "\n";
    }
};

class Gold : public Product
{
public:
    Gold(double price, std::string name, std::string manufacturer)
    :Product(price, name, manufacturer) {}

    double get_price(User* user) override
    {
        return price_;
    }
};
Informer.h
#pragma once
#include "User.h"
#include "Product.h"

class Informer
{
public:
    void buy(User* user, Product* product)
    {
        double price = product -> get_price(user);
        user -> reduce_balance(price);
        std::cout << user -> name_ << " купив "<< product -> name_ << " за " << price << std::endl;
        std::cout << "Ваше замвлення відправлено на склад!\nОчікуйте товар.";
        /*
         *  якийсь код...
         *  який відбправляє запрос кудись :D
         */
    }
};

14

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

  1. Ви виділяєте пам'ять і не звільняєте її. На кожен new має бути свій delete.

  2. Знову немає статичних функцій.

  3. Informer - якась дивна назва. Це має бути або магазин (Store), якщо він виконує операцію купівлі-продажу, або Helper, якщо просто немає куди запхати функцію.

15 Востаннє редагувалося mamkin haker (24.08.2021 16:14:33)

Re: виклик функції без оголошення обєкта класу в якому вона розміщена

змінив:
перейменував інформер в Shop
зробив метод buy статичним

додав:
видалення всіх new

зміна відбулася в 2х файлах

Прихований текст

туть = щось змінилось
main.cc

#include <iostream>
#include <thread>

#include "User.h"
#include "Product.h"
#include "Shop.h" //туть

int main()
{
    User* admin = new User("Київ, вул.Соборна 19", "admin", 10000);
    Product* products[3] = {
        new Bread(16, "хліб круглий", "хз"),
        new Milk(30, "молоко селянське", "Люстдорф", 2.5),
        new Gold(1000, "золото", "НБУ")
    };

    int num = 0;
    int size = sizeof(products)/sizeof(products[0]);

    while (true)
    {
        std::cout << "Вітаю!\nВаш баланс: " << admin -> balance_ << "\n\n";

        for (int i = 0; i < size; i++)
        {
            std::cout << "Номер товару " << i << "\n";
            products[i] -> info();
            std::cout << std::endl;
        }

        std::cout << "Введіть номер тавару та нажміть ентер\n";
        std::cin  >> num;

        if (!(std::cin))
        {
            break;
        }
        
        std::cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";

        if ((num >= 0) && (num < size))
        {
            Shop::buy(admin, products[num]); //туть
        }
        else
        {
            std::cout << "Таких товарів немає!\n";
            break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(3000));

        std::cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
    }

    //туть
    delete admin;

    for (int i = 0; i < size; i++)
    {
        delete products[i];
    }
}

Shop.h

#pragma once
#include "User.h"
#include "Product.h"

class Shop //туть
{
public:
    void static /*туть*/ buy(User* user, Product* product)
    {
        double price = product -> get_price(user);
        user -> reduce_balance(price);
        std::cout << user -> name_ << " купив "<< product -> name_ << " за " << price << std::endl;
        std::cout << "Ваше замвлення відправлено на склад!\nОчікуйте товар.";
        /*
         *  якийсь код...
         *  який відбправляє запрос кудись :D
         */
    }
};

Згоден, Informer невдала назва =(