Чи може С-структура поводитись так, ніби вона мала функцію?


13

Я використовую C і structs, де структура може мати членів, але не функцій. Припустимо для простоти, що я хочу створити структуру для рядків, які я називаю, strі я хочу бути в змозі робити, str.replace(int i, char c)де iє індекс рядка і cє символом, який замінить символ у позиції i. Чи це ніколи не стане можливим, оскільки структури не можуть мати функції або є ще якийсь спосіб, як ми можемо реалізувати таку поведінку та імітувати, що структура може мати (просту) функцію, яка насправді лише структура структурує себе в нову структуру та оновлює її поля, які він міг би зробити?

Таким чином, replaceможе бути третій член структури, який вказує на нову структуру, яка оновлюється під час доступу до неї або подібного. Чи можна це зробити? Або є щось вбудоване чи якась теорія чи парадигма, що заважає моєму наміру?

Фон полягає в тому, що я пишу код C, і я знаходжу собі винаходити функції, які я знаю, що це вбудовані бібліотеки в мовах OOP, і що OOP був би хорошим способом маніпулювання рядками та командами.


5
Я чесно думаю, що вам краще буде писати безкоштовні функції, щоб зробити такі речі. Однак якщо у вас є необхідний моксі
Роберт Харві

5
Структури можуть включати змінні, які є вказівниками на функції. Немає вбудованої спадщини, але ви можете інстанціювати структуру за допомогою покажчиків, що вказують на різні функції з однаковою підписом. Вам часто хочеться зробити перший параметр функції вказівником на структуру.
Джеймс МакЛейд

29
це замінити (& str, i, c) справді набагато гірше, ніж str.replace (i, c)? Ваше запитання насправді не стосується заміни функцій, це намагання розбити новий синтаксис на C.
whatsisname

1
@RobertHarvey Дякую за посилання cs.rit.edu/~ats/books/ooc.pdf . Приємна книга (і ціна правильна).
Джон Форкош

3
@whatsisname: У C ви все одно повинні передати вказівник структури на функцію, так що все одно ви закінчитесь str.replace(&str, i, c). thisЗвичайно +, автоматизує проходження покажчика.
Джонатан Леффлер

Відповіді:


21

Ваша функція повинна виглядати приблизно так.

void
replace(struct string * s, int i, char c);

Це приймає вказівник на об'єкт, над яким працюватиме як перший параметр. У C ++ це відомо як this-показник і його не потрібно чітко оголошувати. (Порівняйте це з Python там, де це потрібно.)

Для того, щоб викликати свою функцію, ви також явно передавали б цей вказівник. В основному ви торгуєте o.f(…)синтаксисом для f(&o, …)синтаксису. Не велике діло.

Історія стає більш задіяною, якщо ви хочете підтримати поліморфізм (він же virtualфункції). Його також можна імітувати в C (я це показав для цієї відповіді ), але це не дуже добре вручну.

Як зауважив Ян Худек , ви також маєте зробити звичку префіксувати ім'я функції з ім'ям типу (тобто string_replace), оскільки у C немає пробілів імен, тому може бути лише одна назва з функцією replace.


17
Звичайно, функцію, ймовірно, доведеться викликати string_replace, тому що у C також немає перевантаження функцій, і ви, ймовірно, матимете якусь іншу replaceдля іншого типу…
Ян Худек,

2
Його не можна назвати string_replace. Імена , що починаються з str, memабо з wcsподальшим рядкової буквою зарезервовані для розширення в майбутньому.
Девід Конрад

43

Структури можуть містити покажчики функцій , але вони дійсно потрібні лише для віртуальних методів. Невіртуальні методи в об'єктно-орієнтованому С зазвичай виконуються шляхом передачі структури як першого аргументу в звичайну функцію. Подивіться на Gobject для хорошого прикладу рамки OOP для C. Він використовує макроси для обробки багатьох котлових плит, необхідних для успадкування та поліморфізму.

C був створений 44 роки тому. Це дуже популярна мова з відкритим кодом. Ви не перша людина, яка думає, що зі стандартними C-струнними елементами можна працювати. Здійсніть кілька пошукових записів для бібліотек рядків C. Вам не доведеться винаходити колесо.


2
Інший помітний приклад - CPython. У коді використовується багато концепцій OOP, але він є 100% чистим C.
Бакуріу,

@Bakuriu Я думаю, ви плутаєте Cython і CPython
кішка

1
@cat Він, ймовірно, означає API Python C, Cython не на 100% чистий C. docs.python.org/c-api/intro.html
JAB,

5
@cat Ні. Перегляньте джерела CPython. Більшість речей дійсно зроблені за допомогою парадигми OOP, і вони забезпечують API OOP, який здебільшого відповідає API python.
Бакуріу

1
@Bakuriu О, ви маєте на увазі час виконання, джерело та C API Python, а не мову Python. ваш коментар не зробив цього дуже зрозумілим
кіт

8

За допомогою покажчиків функцій ви можете:

str.replace(&str, i, c);

Це, як правило, корисно лише в тому випадку, якщо реалізація може змінитися, і в цьому випадку ви повинні використовувати vtable, тому накладні дані - лише один покажчик на структуру:

str.vtable->replace(&str, i, c);

3
Я схильний все ще називати його як string_replace (& str, i, c), тоді використовуйте vtable всередині string_replace, а не повідомляйте сайт виклику про vtable.
Піт Кіркхем,

2
Імена @Pete, що починаються з str(або memабо wcs), і малі літери зарезервовані стандартом C для майбутніх розширень, тому не називайте це string_replace. str_replaceдобре.
Девід Конрад

3

Так, вони можуть, начебто. Ви можете скористатися тим, що C дозволяє вказівникам функціонувати блоки в пам'яті, так само як покажчики функцій, і за допомогою цього ви можете створювати інтерфейс як поліморфізм, так і віртуальні функції (навіть якщо це не так сильно).

Нещодавно я написав повідомлення в блозі за запитом одного з моїх студентів, що стосується коду, подібного до інтерфейсу, на C і Go, ви можете прочитати його тут:

Повідомлення в блозі на інтерфейсах, що не належать до ОО

Подивіться, чи дає вам якісь ідеї.

Ви також можете просто поставити вільну функцію у свій код і використовувати "цей" -показник, тобто ви передаєте вказівник на існуючу структуру для роботи, як описано в інших відповідях.

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