Страницы

Поиск по вопросам

пятница, 13 декабря 2019 г.

Как определить регистр символа

#javascript


Здравствуйте! Подскажите, как определить регистр символа. Именно определить, а не
изменить. Есть ли какая-нибудь функция? Самый простой метод в лоб - это два массива
с верхний и нижним регистром, после проверка на вхождение. Есть ли путь проще?     


Ответы

Ответ 1



Например, так можно: var symbol = 's'; var isUpperCase = symbol.toUpperCase()==symbol; alert(!!isUpperCase); // true - верхний регистр, false - нижний

Ответ 2



На ум пришло 2 идеи: Сравнивать диапазон ASCII кодов символов, если входит в диапазон - значит верхний регистр, иначе нижний. Сложность в том, что тут придется учитывать разные кодировки, или приводить символ\текст к нужной. Воспользоваться функцие приводящей к верхнему\нижнему регистру. Пример допустимый для PHP: function isUpper($str) { if ($str === strtoupper($str)) return true; else return false; } В JS у строки есть метод - toUpperCase().

Ответ 3



На днях столкнулся с такой же задачей. Предлагаю свою идею. В ходе написание скрипта были учтены непереводимые в регистр символы, цифры, пробел. При определении ввода верхнего регистра проверяю последний введенный символ. Ну в общем чего ходить вокруг да около вот функция которая принимает объект и уже на типу объекта берет значение для проверки. /** * return boolean * true - using Caps Lock * false - not using Caps Lock **/ function checkingUp(_obj){ var symbol = ''; var type = _obj[0].tagName; switch(type) { case "INPUT" : symbol = String(_obj.val()); break; } if(symbol == ''){ return false; } symbol = symbol.substr(symbol.length - 1, (symbol.length)); if($.isNumeric(symbol)){ return false; } var newSymbol = symbol.toLowerCase(); if(symbol != newSymbol){ return true; } return false; } Функция принимает String значение для проверки. /** * return boolean * true - using Caps Lock * false - not using Caps Lock **/ function checkingUp(_obj){ var symbol = _obj; if(symbol == ''){ return false; } symbol = symbol.substr(symbol.length - 1, (symbol.length)); if($.isNumeric(symbol)){ return false; } var newSymbol = symbol.toLowerCase(); if(symbol != newSymbol){ return true; } return false; } Функция может быть использована для проверки вводимого значения в поле Password, примерный код проверки с использованием вышеизложенной функции прилаживая ниже . . . $("#login-form input[type=password]").each(function(){ // после поля ввода пароля расположен span с логотипом капчи, скрытый стилями css var iconCapsLock = $(this).parent().find('.capslock'); $(this).bind('keyup', function(){ if(checkingUp($(this))){ iconCapsLock.show(); } else{ iconCapsLock.hide(); } }); $(this).bind('blur', function(){ iconCapsLock.hide(); }); }); И под конец пример HTML верстки с полем для проверки
Надеюсь, что мой совет поможет нуждающимся ))

Ответ 4



Вот решение: function strUpAndDown(str){ var newStr = ''; for(var i =0; i < str.length;i++){ if(str[i].toLowerCase() === str[i]){ newStr += str[i].toUpperCase(); }else { newStr += str[i].toLowerCase(); } } return newStr; }

Ответ 5



function whatCase(ch) { var u = ch.toUpperCase(), l = ch.toLowerCase() return u !== l ? ch === u ? 'upper' : 'lower' : 'not-a-letter' } document.addEventListener('input', function (e) { document.querySelector("output").innerHTML = e.target.value.split("").map(function (ch) { return "" + ch + "" }).join("") }) .upper { color: blue; } .lower { color: green; } .not-a-letter { color: red; } input, output { display: block; width: 100%; box-sizing: border-box; }

Ответ 6



Как вам такой вариант? checked_val.charAt(0).matches("A-Z"); //Верх. регистр checked_val.charAt(0).matches("a-z"); //Нижн. регистр Если "для английских не прокатит" if (targetId.charAt(0).toUpperCase() == targetId.charAt(0)) { ... } else { ... }

Интерфейс и его примеры

#c_sharp


Привет всем!

В продолжение темы Ссылка на класс или делегат, где уважаемый @Alex Krass пытался
мне объяснить, какая польза от применения интерфейса.

Для меня все так же остается загадкой. Я все так же считаю, что это лишняя писанина кода.
За это время я почитал немало статей про интерфейс и просмотрел видеокурс.
Но так и не разобрался. Честно сказать, я не знаю, почему я зациклился на нем, ведь
не знал бы о его существовании, давно бы закончил писать свой проект.

Вот, к примеру, Алекс объясняет, что в его примере он с легкостью может добавить
еще 100 классов useConnect, но, на мой взгляд, ему также нужно 100 раз вызывать connect
= new UseConnect(ссылка на класс());, причем в его конкретном случае ему придется плодить
switch, чтобы вызвать все классы. Причем я так и не понял, как в таком случае можно
добраться до метода из какого-либо класса, в том примере их можно вызвать только все
кучей. Причем если в главном классе мне нужно будет еще раз использовать какой-нибудь
метод, то мне опять придется переписывать connect = new UseConnect(ссылка на класс());.
В моем же случае, где я просто пишу ссылку на класс и через переменную вызываю метод,
так я эту переменную могу использовать где захочу и когда захочу, причем могу вызвать
любой из методов. Да и вообще мне 
не придется писать класс UseConnect, я могу вызывать методы сразу, в данном примере
из класса MySQL, к примеру.

Вот реальный пример, который мне нужно реализовать в своем примере. Опять же повторюсь,
с помощью ссылки на классы я уже эту задачу решал. Просто хочу посмотреть, как решают
такую задачу профи, с помощью интерфейсов.

Вот пример. У меня есть форма, в которой пользователь может сохранять записи в базе
данных. В моем случае MySQL. Он может внести запись, после вызвать ее и сделать изменения. 
У меня есть пять классов. Главный, который вызывает форму, класс инсерт, класс упдата,
класс селест и класс подключения к базе. Класс инсерт упдата и селект наследуют класс
подключения к базе. Ну это я так решил сделать, чтобы не использовать интерфейс. Вот
и сама задача: как мне эти четыре класса с помощью интефейса(ов) подключить к главному
классу с формой.

Ну, я это так для моего примера взял.
Лучше, конечно, приведите, явный пример, где интерфейс облегчает жизнь программисту.
Прошу не заводить тему моей грамотности и знания русского языка. Эту тему мы уже
обсуждали и я не раз говорил о причине моей безграмотности русского языка. И так же
не посылайте меня за книжкой, ну если только посоветуете хорошую.   
    


Ответы

Ответ 1



Сейчас Вам, скорее всего, это не надо, Вы столкнетесь с этим когда-нибудь позже, когда будете готовы. Не заморачивайтесь и идите дальше, очень часто программисты вынуждены пропускать темы и возвращаться к ним. Главное, что Вы знаете, что есть такая вещь, как интерфейс, и она позволяет скрывать реальные реализации классов. С помощью интерфейсов Вы: не завязываете логику своего приложения с конкретными классами и можете легко вносить изменения в одни классы, не трогая другие, добавлять функциональность или заменить один класс абсолютно другим, не трогая все приложение. То есть реализуется абстракция от реализации; можете проектировать логику приложений на интерфейсах, оставив реализацию на потом и применяя заглушки; применять так называемое множественное наследование; если будете начальником, сможете легко донести свои мысли до подчиненных (реализуй мне функциональность вот этого интерфейса). Я дам несколько примеров, в которых применяется интерфейс, но сразу оговорюсь, они не являются лучшими представителями. Ведь я тоже учусь. ) Проектирование недозоопарка Давайте запроектируем небольшую программу зоопарка, при этом зоопарк у нас бужет пошаговым. 1. В первую очередь его стоит населить животными, которые умеют ходить по нему, приступим. Для описания жизненного цикла зоопарка я использую класс ZooLivecycle: class ZooLivecycle { public void allPetWalk() { } } Итак, у нас есть животные, которые умеют ходить, давайте определим их возможности через интерфейсы и реализуем. interface IWalk { void walk(); } class Cat : IWalk { public void walk() { Console.WriteLine("cat walk"); } } class Dog : IWalk { public void walk() { Console.WriteLine("dog walk"); } } class Fish : IWalk { public void walk() { Console.WriteLine("fish cant walk"); } } class Bird : IWalk { public void walk() { Console.WriteLine("bird can fly"); } } Для того чтобы все животные ходили, проще их передать в класс зоопарка всем массивом и пройтись по ним циклом. class ZooLivecycle { public void allPetWalk(IWalk[] arr) { for (int i = 0; i < arr.Count(); i++) arr[i].walk(); } } Итак, теперь можно вызывать нашу реализацию. class Program { static void Main(string[] args) { ZooLivecycle zoo = new ZooLivecycle(); IWalk[] walks = new IWalk[]{new Cat(), new Dog(), new Fish(), new Bird()}; Console.WriteLine("\n*Pet Walk*"); zoo.allPetWalk(walks); Console.Read(); } } А теперь попробуйте реализовать это без интерфейсов, главным образом функцию allPetWalk, хотя есть способ - это общий класс родитель. Можно также попробовать передавать ссылку как public void allPetWalk(Object[] arr) и потом приводить типы, но это является очень плохой практикой, так как вы теряете контроль над типами и вынуждены добавлять проверки, что не является лучшим решением. 2. Идем дальше, мы решили добавить систему наблюдения, а именно видеокамеры, которая сможет передавать информацию. interface IObservation { void analyze(); } class Videocamera : IObservation { public void analyze() { Console.WriteLine("In zoo all ok"); } } Реализуем получение информации в классе зоопарка: class ZooLivecycle { public void allPetWalk(IWalk[] arr) { for (int i = 0; i < arr.Count(); i++) arr[i].walk(); } public void zooAnalyze(IObservation[] arr) { for (int i = 0; i < arr.Count(); i++) arr[i].analyze(); } } Ну и вызов. class Program { static void Main(string[] args) { ZooLivecycle zoo = new ZooLivecycle(); IWalk[] walks = new IWalk[]{new Cat(), new Dog(), new Fish(), new Bird()}; IObservation[] analyze = new IObservation[] { new Videocamera() }; Console.WriteLine("\n*Pet Walk*"); zoo.allPetWalk(walks); Console.WriteLine("\n*Analyze zoo*"); zoo.zooAnalyze(analyze); Console.Read(); } } 3. А теперь давайте подложим свинью, если кто-то все еще использовал класс родитель, вместо интерфейсов. Реализуем помошника, который может как ходить по зоопарку, так и передавать информацию. В языке C# нет перекрестного наследования, но зато можно наследовать несколько интерфейсов вместо этого. class HelperPet : IWalk, IObservation { public void walk() { Console.WriteLine("helppet walk"); } public void analyze() { Console.WriteLine("helppet analyze"); } } Это все, что пришлось добавить. Можно дальше пользоваться нашим зоопарком, ничего не переписывая. class Program { static void Main(string[] args) { ZooLivecycle zoo = new ZooLivecycle(); IWalk[] walks = new IWalk[]{new Cat(), new Dog(), new Fish(), new Bird(), new HelperPet()}; IObservation[] analyze = new IObservation[] { new Videocamera(), new HelperPet() }; Console.WriteLine("\n*Pet Walk*"); zoo.allPetWalk(walks); Console.WriteLine("\n*Analyze zoo*"); zoo.zooAnalyze(analyze); Console.Read(); } } Теперь давайте рассмотрим реальные примеры, которые очень часто используются. Очень часто интерфейсы используются как описательные модели, наследование от которых дает возможность работать с тем, для чего они созданы. Тем самым вы не привязываетесь к конкретным классам. В самом языке очень C# даже есть интерфейсы, которые реализуют то или иное поведение. Вы очень часто будете с этим сталкиваться, если перейдете на WPF или ASP.NET MVC приложения. Использование foreach с собственными классами Давайте улучшим наш зоопарк и добавим класс для хранения животных. Несмотря на то, что он довольно объемный, я просто взял с MSDN пример и просто подставил свои значения. public interface IWalk { void walk(); } public class Animals : IEnumerable { private IWalk[] _pets; public Animals(IWalk[] pArray) { _pets = new IWalk[pArray.Length]; for (int i = 0; i < pArray.Length; i++) { _pets[i] = pArray[i]; } } IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } public PetsEnum GetEnumerator() { return new PetsEnum(_pets); } IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } } public class PetsEnum : IEnumerator { public IWalk[] _pets; int position = -1; public PetsEnum(IWalk[] list) { _pets = list; } public bool MoveNext() { position++; return (position < _pets.Length); } public void Reset() { position = -1; } object IEnumerator.Current { get { return Current; } } public IWalk Current { get { try { return _pets[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } } Теперь я могу делать так: class Program { static void Main(string[] args) { ZooLivecycle zoo = new ZooLivecycle(); Animals animals = new Animals(new IWalk[]{new Cat(), new Dog(), new Fish(), new Bird(), new HelperPet()}); Console.WriteLine("\n*Pet Walk*"); zoo.allPetWalk(animals); Console.Read(); } } class ZooLivecycle { public void allPetWalk(Animals animals) { foreach(IWalk animal in animals) animal.walk(); } } Не реализовав интерфейс, вы не сможете использовать с вашим классом foreach, хотя на самом деле это делается очень быстро. При этом метод foreach работает с любыми объектами, и не будь интерфейсов, достигнуть такого эффекта было бы сложнее. Теперь в класс Animals можно добавить такие методы, как Add, Remove, etc. Ну и в конце концов вы можете ставить заглушки и передавать тестовые данные. Если реализация классов достаточно сложна, например, один из них получает данные из базы, а другой обрабатывает эти данные, то вы можете написать ненастоящий класс. То есть вместо реальных данных Вы передаете класс, которые не использует подключение к БД, и потом его можно будет переписать. Причем можно работать нормально как с одним, так и с другим классом попеременно.

Как отредактировать заголовок последнего коммита?

#git #git_commit


Написал неправильное сообщение, когда сделал commit, но ещё не сделал push. Как исправить?
    


Ответы

Ответ 1



Вы можете дать новый заголовок git commit --amend -m "ваш заголовок" или git commit --amend -c HEAD если хотите отредактировать старый

Ответ 2



В похожем вопросе было очень интересное замечание, если вам нужно отредактировать коммит более старый, а не последний, используйте rebase interactive (например тут если искомый коммит 3мя ранее): git rebase -i HEAD~3 Пометьте нужный коммит как edit, а потом делайте git commit --amend А после окончания редактирования коммита сделайте git rebase --continue чтобы завершить rebase. Ну и как написал @Daniil следует потом сделать push force если коммиты уже в удаленном репозитории.

Ответ 3



git commit --amend -m "исправленный текст" Если исправленный текст должен быть больше одной строки, то: git commit --amend Откроется текстовый редактор, и вы сможете внести исправления.

MVC и ООП это одно и тоже?

#php #веб_программирование #ооп #mvc


MVC и ООП это одно  и тоже? объясните пожалуйста.
    


Ответы

Ответ 1



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

Ответ 2



НЕТ ООП (Объектно-ориентированная парадигма) - это модель описания предметной области, то есть как вы описываете предметную область компьютеру. Мы можем например смоделировать некоторую область как систему функций (ФП), или как некие действия (процедуры) изменяющие состояния каких-либо переменных (ПП), либо как некие объекты обменивающиеся сообщениями и взаимодействующие друг с другом (собственно ООП). Эти модели воплощаются в конкретных языках программирования. MVC (Model-View-Controler) - это модель описания программного продукта (или если хотите шаблон), она диктует какие "детали" должна содержать ваша программа.

C++: изменение символа строкового литерала

#cpp #cpp_faq


#include 

int main()
{
    char* str = "qwerty";
    str[0] = '1';
    std::cout << str << std::endl;
    return 0;
}


Этот код выдает ошибку access violation. В чем дело? Почему нельзя изменить символ
простой не-const строки?

UPD: код сработал при такой инициализации строки: char str[]. Но в чем разница?
    


Ответы

Ответ 1



Строковые константы в коде могут размещаться где-то в отдельном блоке памяти (в дата-секции исполняемого файла, например), который может быть отмечен как "только для чтения". Модифицировать их нельзя, это undefined behavior. Хотя на некоторых компиляторах в некоторых осях при определённых условиях это и может работать, но полагаться на это нельзя. Если хотите иметь модифицируемую строку, то скопируйте её или объявите как массив (не как указатель). См. Why is this string reversal C code causing a segmentation fault?

Ответ 2



(Оказалось, что при редактировании комментария нельзя отвлекаться дольше, чем на 5 минут!!! Пришлось в ответ...) Кстати, нормальный крестовый компилятор (например, g++) выдаст предупреждение deprecated conversion from string constant to ‘char*’ для char* str = "qwerty"; И вообще, при изменении на char str[] = ... Вы получаете другую программу, с другим набором переменных. В первом случае у Вас в стеке указатель (4 байта для 32-бит машины) с именем str (или "по символическому адресу", что одно и то же), который содержит адрес строковой константы "qwerty" (к вашему удивлению она оказалась в read-only области памяти), а во втором по символическому адресу str в стеке отвели 7 байт (qwerty + nil). Вот эту разницу Вы и увидели при запуске.

Ответ 3



Попробуй использовать char str[] = "qwerty"; вместо char* str = "qwerty";

Как получить полное имя файла в одну команду?

#linux #файлы #shell


Как получить полное (с путём относительно /) имя файла в одну команду?

Бывает, работаешь в консоли, и нужно скопировать /полный/путь/к/файлу, например,
чтобы в соседней консоли использовать его как аргумент для scp. Приходится вызывать
pwd, чтобы скопировать путь к текущей папке, и ls, чтобы скопировать имя файла. Можно
ли это сделать в одну команду?
    


Ответы

Ответ 1



readlink -f покажет /полный/путь/к/файлу.ext, дополнительно "раскрыв" все символические ссылки и заменив их на "канонические" пути. Пример показателен: $ cd /tmp $ mkdir foo $ touch foo/bar.ext $ ln -s foo/bar.ext baz.ext $ readlink -f foo/bar.ext /tmp/foo/bar.ext $ readlink -f baz.ext /tmp/foo/bar.ext Здесь /tmp/baz.ext является симлинком на /tmp/foo/bar.ext. Предложенное решение работает в Linux и FreeBSD, но не работает в Mac OS - у них там своя атмосфера.

Ответ 2



Предложу вариант чуть понавороченней: readlink -m файл | tr -d '\r\n' | xsel -b То есть: Читаем полный путь Сразу же копируем его в буфер обмена, предварительно ... ... вырезав конечные СR/LF (если не хотим, чтобы они добавлялись при вставке)

Ответ 3



Для файлов относительно текущего каталога echo ~+/file или с тем же результатом echo $PWD/file

Ответ 4



можно, например, подставлять то, что содержится в переменной окружения $PWD (или в любой другой переменной окружения), даже без «команды», а всего лишь клавиатурным сочетанием. если, конечно, ваша оболочка использует gnu/readline для редактирования командной строки. например, такая команда привяжет к клавиатурному сочетанию alt+o подстановку значения переменной $PWD (и слэша в конце — для удобства) в текущую позицию курсора: $ bind '"\eo": "$PWD/\e\C-e"' здесь \eo — это и есть alt+o (а, например, \C-o — это ctrl+o). чтобы данная привязка создавалась автоматически в каждой сессии оболочки, можно добавить приведённую команду, например, в стартовый скрипт используемой оболочки — ~/.${SHELL##*/}rc. а ещё лучше — добавить строку, которая в примере выше передавалась встроенной команде оболочки bind, прямо в файл ~/.inputrc (конф. файл, используемый gnu/readline-ом): "\eo": "$PWD/\e\C-e" навеяно этим ответом: Bash: call script with customized keyboard shortcuts?

Создание makefile

#cpp #компиляция #makefile


Пытаюсь разобраться в написании грамотного make файла, это ад.

Есть такие файлы: SubClass.h/.cpp, SuperClass.h/.cpp, Main.cpp.

Сконструировал такой makefile:

Programm: Main.o SuperClass.o SubClass.o
    g++ -o Programm Main.o SuperClass.o SubClass.o
Main.o: Main.cpp SuperClass.o SubClass.o
    g++ -c -o Main.o Main.cpp
SuperClass.o: SuperClass.h SuperClass.cpp
    g++ -c -o SuperClass.o SuperClass.cpp
SubClass.o: SubClass.cpp SubClass.h SuperClass.o
    g++ -c -o SubClass.o SubClass.cpp


Классно бы это автоматизировать и разделить по директориям /h /cpp /o файлы.

Нашел хороший способ получать зависимости (через include bash добавил в makefile)

g++ -MM SubClass.cpp
SubClass.o: SubClass.cpp SubClass.h SuperClass.h


А нужно что бы выхлоп был SubClass.o: SubClass.cpp SubClass.h SuperClass.o, не понимаю,
как мне этого добиться с помощью make? Я явно делаю что то не так.

Через wildecard научился получать список файлов в папке, а вот в подпапках как (нахождение
самих подпапок и тд)?

Это ведь такая простая и популярная модель организации проекта, неужели нет ничего
готового? Возможно я пишу велосипед? :D 

PS: Я не прошу что то писать за меня, просто наведите в нужное направление.
    


Ответы

Ответ 1



мне кажется, ваш файл несколько многословен. для всех описанных действий, кажется, достаточно таких строк: Programm: Main.o SuperClass.o SubClass.o g++ -o $@ $^ запуск make с параметром -n (dry-run) показывает такую последовательность команд (при наличии в текущем каталоге только cpp- и h-файлов): g++ -c -o Main.o Main.cpp g++ -c -o SuperClass.o SuperClass.cpp g++ -c -o SubClass.o SubClass.cpp g++ -o Programm Main.o SuperClass.o SubClass.o немного объяснений по поводу «применённой магии» «магия» называется implicit rules. все актуальные implicit rules (и ещё многое другое) можно посмотреть командой make -p | less. к примеру, о том, что из file.cpp можно собарть file.o (и, главное, как это сделать), make «знает» благодаря вот такому правилу: %.o: %.cpp # recipe to execute (built-in): $(COMPILE.cpp) $(OUTPUT_OPTION) $<

Ответ 2



А нужно что бы выхлоп был SubClass.o: SubClass.cpp SubClass.h SuperClass.o А зачем? Зачем при перекомпиляции SuperClass.cpp перекомпилировать SubClass.cpp? Почему бы не сделать так: Gpp = g++ srcs = SubClass.cpp SuperClass.cpp main.cpp objs = $(srcs:.cpp=.o) deps = $(srcs:.cpp=.d) program: $(objs) $(Gpp) $^ -o $@ %.o: %.cpp $(Gpp) -MMD -MP -c $< -o $@ .PHONY: clean # $(RM) is rm -f by default clean: $(RM) $(objs) $(deps) program -include $(deps) Поясняю: g++ сам сгенерит файлы с зависимостями (.d). %.o: %.cpp $(Gpp) -MMD -MP -c $< -o $@ Это правило сборки каждого .o файла, которое выполняет g++ с параметром -MMD, которая генерирует файл с зависимости (без системных файлов). Файлы с зависимостями перегенерируются только при изменении исходников. objs=,deps= генерируем список файлов с помощью встроенной возможности замены в make $@ и $< так называемые "автоматические переменные". $< - имя первой зависимости (first prerequisite). $@ - имя цели для правила (выходного файла) (target file name). Пример: hello.o: hello.c hello.h gcc -c $< -o $@ $@ = hello.o - имя выходного файла. $< = hello.c hello.h - входные файлы В последней строчке мейкфайла включаем файлы с зависимостями (- в начале строки означает игнорировать ошибки.

Ответ 3



Обычно мы сравнительно редко пишем makefile, а вся вроде бы освоенная "магия" так и норовит за полгода улетучиться из головы. Поэтому я стараюсь писать простые Makefile, вроде такого (для вашего случая). # Эти обозначения я вечно забываю: # $@ target # $^ all right part # $? only new in right part # $< first name from right part # #CC = gcc #CFLAGS = -g -std=gnu99 CC = g++ CXXFLAGS = -O3 -pthread SRCS = SubClass.cpp SuperClass.cpp main.cpp PROGS = programm all: $(PROGS) programm: main.o SubClass.o SuperClass.o $(CC) -o $@ $^ -pthread .PHONY: clean clean: rm -rf $(PROGS) *.o *~ *.bak a.out depend: @makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null # DO NOT DELETE SubClass.o: f.h data.h main.o: f.h Строки после depend с зависимостями .o от .h добавляет команда makedepend (символ @ перед ней подавляет ее вывод в stdout), которая исполняется, когда мы запускаем > make depend после изменения состава файлов проекта или добавления наших (не системных) .h файлов в какой-нибудь .cpp Когда мы вызываем make без аргументов, то Makefile начинает выполняться с первой метки (остальные, если не зависят от нее, уже не будут рассматриваться). Здесь all: вроде бы излишня (можно было бы сразу начать файл с programm:), но иногда хочется одним вызовом make собрать сразу несколько модулей и тогда они просто перечисляются в переменной PROGS. Здесь я в main.cpp включаю f.h, в SubClass.cpp включаю f.h и data.h, а в SuperClass.cpp ничего не включаю. Make по умолчанию строит зависимости .o от .cpp (или .c) и вызывает g++ с подстановкой значения из переменной CXXFLAGS (а для gcc использует CFLAGS). Ключи для линкера (вызов $(CC) -o ...) я предпочитаю прописывать явно либо в команде, либо в переменных makefile, которые туда подставляю. Это может сберечь кучу времени при отладке через год-другой (особенно если при вызове make образуется длиннющая "простыня"). Если для компиляции какого-либо файла требуются нестандартные действия, то это прописываем вручную. Например, мы хотим (может быть иногда) использовать при компиляции файла SubClass.cpp переменную препроцессора TEST. Тогда напишем SubClass.o: SubClass.cpp Makefile $(CC) $(CXXFLAGS) -c -DTEST $< где нибудь между all: и depend:. В таком случае мы должны включать в аргументы выполняемой команды переменную CXXFLAGS явно. Я написал здесь еще и зависимость от самого Makefile, чтобы при редактировании -DTEST проходила перекомпиляция SubClass.o и дальше пересборка programm. Вот результат avp@avp-ubu1:tmake$ make clean rm -rf programm *.o *~ *.bak a.out avp@avp-ubu1:tmake$ make g++ -O3 -pthread -c -o main.o main.cpp g++ -O3 -pthread -c -DTEST SubClass.cpp g++ -O3 -pthread -c -o SuperClass.o SuperClass.cpp g++ -o programm main.o SubClass.o SuperClass.o -pthread avp@avp-ubu1:tmake$ ./programm f1() f2(): xaxa Теперь отредактируем Makefile, уберем -DTEST при компиляции SubClass.cpp avp@avp-ubu1:tmake$ make g++ -O3 -pthread -c SubClass.cpp g++ -o programm main.o SubClass.o SuperClass.o -pthread avp@avp-ubu1:tmake$ ./programm f2(): xaxa avp@avp-ubu1:tmake$