std::function & std::bind
Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan C++ di Coddy. Pelajaran 86 dari 104.
Meskipun lambda sangat berguna, terkadang kamu perlu menyimpan object yang dapat dipanggil dengan tipe berbeda secara seragam, atau menyesuaikan fungsi yang sudah ada agar cocok dengan signature yang diperlukan. std::function dan std::bind dari header <functional> mengatasi masalah ini.
std::function adalah pembungkus dengan tipe yang dihapus, yang dapat menyimpan callable apa pun yang cocok dengan tanda tangan tertentu, seperti fungsi, lambda, atau object fungsi:
#include <iostream>
#include <functional>
int add(int a, int b) { return a + b; }
int main() {
std::function<int(int, int)> operation;
operation = add; // Fungsi biasa
std::cout << operation(3, 4) << "\n"; // 7
operation = [](int a, int b) { return a * b; }; // Lambda
std::cout << operation(3, 4) << "\n"; // 12
}std::bind membuat objek callable baru dengan menetapkan beberapa argumen dari fungsi yang sudah ada. Gunakan std::placeholders::_1, _2, dan seterusnya untuk menandai argumen yang tetap variabel:
#include <iostream>
#include <functional>
void greet(const std::string& greeting, const std::string& name) {
std::cout << greeting << ", " << name << "!\n";
}
int main() {
using namespace std::placeholders;
auto sayHello = std::bind(greet, "Hello", _1);
sayHello("Alice"); // Hello, Alice!
auto swapped = std::bind(greet, _2, _1);
swapped("Bob", "Hi"); // Hi, Bob!
}Alat-alat ini sangat berguna dalam OOP untuk menyimpan callback sebagai anggota class atau menerapkan pola Strategy. Namun, C++ modern sering lebih memilih lambda daripada std::bind karena lebih mudah dibaca dan lebih efisien. Gunakan std::bind terutama saat kamu perlu mengubah urutan argumen atau bekerja dengan kode lama.
Tantangan
MudahMari buat kalkulator yang dapat dikonfigurasi untuk menunjukkan keunggulan std::function dan std::bind. Kamu akan membuat sistem yang dapat menyimpan, menukar, dan menyesuaikan operasi matematika saat program berjalan: sistem ini menunjukkan cara alat tersebut memungkinkan pengelolaan callback yang fleksibel.
Kamu akan mengatur kodemu dalam tiga file:
MathOperations.h: Definisikan kumpulan fungsi matematika mandiri yang akan menjadi library operasimu.Buat fungsi-fungsi ini:
add(int a, int b): mengembalikan hasil penjumlahansubtract(int a, int b): mengembalikan hasil pengurangan (a - b)multiply(int a, int b): mengembalikan hasil perkalianpower(int base, int exponent, int multiplier): mengembalikanmultiplier * (base ^ exponent). Gunakan perulangan sederhana untuk menghitung pangkatnya (anggap eksponennya tidak negatif).
Calculator.h: Definisikan classCalculatoryang menggunakanstd::functionuntuk menyimpan dan menjalankan operasi secara dinamis.Calculator-mu harus memiliki:
- Member privat
std::function<int(int, int)>untuk menyimpan operasi biner saat ini setOperation(std::function<int(int, int)> op): menetapkan operasi saat inicalculate(int a, int b): menjalankan operasi yang tersimpan dan mengembalikan hasilnya
Sertakan header yang diperlukan (
<functional>) dan pastikan untuk menyertakan header MathOperations-mu.- Member privat
main.cpp: Baca tiga input:- Nama operasi:
add,subtract,multiply, atausquare - Bilangan pertama (bilangan bulat)
- Bilangan kedua (bilangan bulat)
Buat
Calculatordan konfigurasikan berdasarkan nama operasi:- Untuk
add,subtract, danmultiply: tetapkan fungsi yang sesuai secara langsung ke calculator - Untuk
square: gunakanstd::binduntuk membuat versi khusus daripoweryang selalu menggunakan eksponen 2 dan pengali 1. Fungsi yang diikat harus menerima dua argumen, dengan hanya argumen pertama yang digunakan sebagai basis (argumen kedua dapat diabaikan menggunakan placeholder).
Setelah menetapkan operasi, panggil
calculate()dengan kedua bilanganmu dan cetak:Result: [value]Lalu tunjukkan cara menukar operasi dengan menetapkan lambda yang mengembalikan
a + b + 100ke calculator, menjalankannya dengan input yang sama, lalu mencetak:With bonus: [value]- Nama operasi:
Contohnya, dengan input add, 10, dan 5:
Result: 15
With bonus: 115Dengan input multiply, 7, dan 3:
Result: 21
With bonus: 110Dengan input square, 4, dan 0:
Result: 16
With bonus: 104Tantangan ini menunjukkan cara std::function menyediakan cara seragam untuk menyimpan berbagai tipe callable (fungsi biasa, fungsi yang diikat, dan lambda), sementara std::bind memungkinkanmu menyesuaikan fungsi yang sudah ada dengan menetapkan beberapa argumennya.
Coba sendiri
#include <iostream>
#include <string>
#include <functional>
#include "Calculator.h"
using namespace std;
int main() {
// Baca input
string operation;
int num1, num2;
cin >> operation >> num1 >> num2;
// Buat instance Calculator
Calculator calc;
// TODO: Konfigurasikan kalkulator berdasarkan nama operasi
// Untuk "add", "subtract", "multiply": tetapkan fungsi yang sesuai secara langsung
// Untuk "square": gunakan std::bind untuk membuat versi khusus dari power
// yang selalu menggunakan eksponen 2 dan pengali 1
// Petunjuk: Gunakan std::placeholders::_1 untuk argumen basis
if (operation == "add") {
// Tulis kodemu di sini
} else if (operation == "subtract") {
// Tulis kodemu di sini
} else if (operation == "multiply") {
// Tulis kodemu di sini
} else if (operation == "square") {
// Tulis kodemu di sini, gunakan std::bind dengan fungsi power
}
// TODO: Panggil calculate() dan tampilkan hasilnya
// Format: "Result: [value]"
// TODO: Tunjukkan cara mengganti operasi
// Tetapkan lambda yang mengembalikan a + b + 100 ke kalkulator
// Panggil calculate() lagi dan cetak hasilnya
// Format: "With bonus: [value]"
return 0;
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Object
1Dasar-Dasar OOP
File EksternalBuild dan Kompilasi C++File Header dan File SourceNamespace dan CakupanPengantar OOP dalam C++class vs objectPointer 'this'method (Fungsi Anggota)Atribut (Anggota Data)Dasar Ctor dan DtorRingkasan: Kalkulator Sederhana4Properti class
Anggota instance vs staticGetter dan setterFungsi anggota constKata kunci mutableMethod dan variabel staticFungsi dan class friendRangkuman, Pengelola Rekening Bank7Pewarisan
Pewarisan DasarTingkat Akses pada PewarisanUrutan Pemanggilan Ctor & DtorPenimpaan methodFungsi Virtual & VTablePewarisan BergandaPewarisan VirtualRangkuman: Hierarki Karyawan2Manajemen Memori
Memori Stack vs HeapPointer dan ReferenceMemori Dinamis (new/delete)Smart Pointer di C++RAII di C++Rangkuman: Pengelola Array Dinamis5Enkapsulasi
Penentu Akses dalam C++Penentu Akses secara MendalamPenyembunyian Informasistruct vs classNested dan Inner classRangkuman, Sistem Catatan Siswa8Polimorfisme
Polimorfisme saat Compile vs RuntimeOverloading FungsiMeninjau Kembali Fungsi VirtualFungsi Virtual MurniKelas AbstrakDesain Interface di C++Casting Dinamis & RTTIRangkuman: Kalkulator Bentuk3Konstruktor & Destruktor
Konstruktor DefaultKonstruktor BerparameterKonstruktor SalinKonstruktor PindahDaftar Inisialisasi KonstruktorKonstruktor DelegasiKupas Tuntas DestruktorAturan Tiga, Lima, dan NolRangkuman: class String6Overloading Operator
Pengantar Overloading OperatorOverloading Operator AritmetikaOverloading Operator PerbandinganOperator StreamOverloading Operator PenugasanOverloading Operator [] dan ()Operator Konversi TipeRingkasan, class Matrix9Template
Template FungsiTemplate classSpesialisasi TemplateTemplate VariadikDasar SFINAE & Type TraitsRangkuman, Container Generik12Fitur Modern C++
Semantik Pemindahan & RvaluePenerusan SempurnaEkspresi Lambda secara Mendalamstd::function & std::bindconstexpr dan constevalPengikatan Terstrukturoptional, variant, anyLatihan sendiri: Compiler C++ online