Wake of Gods Forum | Форум Во Имя Богов

Full Version: С++, общая тема
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Наобум.
template <typename T>
class T
{
    Sub<int> s1;
    Sub<T> s2;
};

Просто редко приходится работать с шаблонами.
etoprostoya, спасибо, но такой способ не подойдёт. Нужно просто переименовать тип, не параметризовывая его.

Считай, что помимо Temp есть ещё Temp2, Temp3 и так далее - и в каждом из них есть член, имеющий тип Sub<>. И вот как мне не указывать постоянно конкретное имя внутри угловых скобок - а дать понять компилятору, что нужно использовать "текущий" класс?
Оказывается - то, что я хочу сделать, всё же есть в стандарте C++11, но ещё не реализовано в GCC:

Quote:If a function-definition or member-declarator declares a member function of a class X, the expression this is a prvalue of type “pointer to cv-qualifier-seq X” between the optional cv-qualifier-seq and the end of the function-definition or member-declarator. It shall not appear before the optional cv-qualifier-seq and it shall not appear within the declaration of a static member function (although its type and value category is defined within a static member function as it is within a non-static member function). [Note: the type and value category is defined even for the case of a static member function because declaration matching does not occur until the complete declarator is known, and this may be used in the trailing-return-type of the declarator. —end note]

Otherwise, if a member-declarator declares a non-static data member (9.2 [class.mem]) of a class X, the expression this is a prvalue of type “pointer to X” within the optional brace-or-equal-initializer. It shall not appear elsewhere in the member-declarator.

Буду ждать...
Снова нубс-проблемка)

Случайно обнаружил что у моей главной формы почему-то стоит Visible=false в свойствах, и при этом она отлично отображается...

Создал вторую форму, и как мне все же сделать чтобы при запуске показывалась сразу вторая форма, а первая только после нажатия, допустим "старт" ?
packa, не знаю, как это в си, но вроде везде такое должно быть. Поищи где-нибудь в строке меню должны быть настройки проекта.
Что ж, Пакка, как и просил - держи рецензию на свой код Ab
Прокомментирую его так, будто это настоящий продакшн-код:

PHP Code:
//---------------------------------------------------------------------------

#include <vcl.h>
#include <math.h>
#pragma hdrstop

#include "Unit1.h"
#include <vector>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
using namespace std;
TForm1 *Form1;
int mainXmainYraznica_ammo_enemy_YammoNn;
bool build;
const 
int enemyN=5;

class 
Tower
{
public:
    
int xx;
    
int yy;
    
int health;
    
int damage;
    
int target;
    
int reload;

    
Tower int xint yint hint dint tint r);

    
void Draw_Tower();
    
void Zahvat_Target();
    
void Draw_Lazer();
    
void Reload_Tower();
};

class 
Enemy
{
public:
    
int xx;
    
int yy;
    
int health;

    
Enemyint xint yint h );

    
void Draw_Enemy();
    
void Move_Enemy();
};


class 
Ammo
{
public:
    
int xx;
    
int yy;
    
int number;
    
int target;

    
Ammo (int xint yint nint t);

    
void Move_Ammoint j);
    
void Spawn_Ammoint j);
    
void Draw_Ammo();
};


vector <Enemyenemy_group;
vector <Towertower_group;
vector <Ammoammo_group;
vector <intinterval;

Graphics::TBitmap *enemy2 ;
Graphics::TBitmap *ammo ;
Graphics::TBitmap *tower ;
Graphics::TBitmap *boom ;
Graphics::TBitmap *main ;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponentOwner)
        : 
TForm(Owner)
{
}
//---------------------------------------------------------------------------
Enemy::Enemyint xint yint h )
{
 
xx=x;
 
yy=y;
 
health=h;
}

//----------------------------

void Enemy::Draw_Enemy()
{
for (
int i=0i<enemyNi++)
{
    if (
enemy_group[i].xx!=mainX)
    {
        if (
enemy_group[i].health>0)
        {
            
Form1->Canvas->Draw(enemy_group[i].xxenemy_group[i].yyenemy2);
        }
        else
        {
            
Form1->Canvas->Draw(enemy_group[i].xxenemy_group[i].yyboom);
        }
    }
}
}
//---------------------

void Enemy::Move_Enemy()
{
        if ( 
xx != mainX )
        {
            if (
xx>0)
            {
                
xx+=1;
            }
        }
}
//===========================

Tower::Towerint xint yint hint dint tint r)
{
    
xx=x;
    
yy=y;
    
health=h;
    
damage=d;
    
target=t;
    
reload=r;
}
//---------------

void Tower::Zahvat_Target()
{
int rasstoyanie[5]; //Массив расстояний от башни до врага
        
for (int j=0enemyNj++)
        {
        if (
enemy_group[j].health>0)
        {
        
int raznicaXtarget xx enemy_group[j].xx//Разница по Х
        
int raznicaYtarget yy enemy_group[j].yy//Разница по Y
                
if (raznicaYtarget<0){         //Если башня выше цели
                
raznicaYtarget=enemy_group[j].yy yy;
                }
        
rasstoyanie[j]=sqrt(pow(raznicaXtarget,2)+pow(raznicaYtarget,2)); //Расстояние от врага до башни, по Пифагору
        
}
        
int min rasstoyanie[0];
        
int b=0;
        for (
int j=0j<enemyNj++){
                if (
rasstoyanie[j]<min){
                        
min=rasstoyanie[j]; //Находим ближайшего врага
                        
b=j;
                }

                if (
rasstoyanie[j]<350)
                { 
//Если враг в области поражения башни (пока числом)
                
target=b//Запоминаем номер врага
                
}
        }
        }


}
//-------------

void Tower::Draw_Tower()
{
Form1->Canvas->Draw(xxyytower);
}

//-------------

void Tower::Draw_Lazer()
{
    
Form1->Canvas->Pen->Color=(TColor)RGB(200,0,0);
    
Form1->Canvas->MoveTo(xx,yy);
    
Form1->Canvas->LineTo(enemy_group[target].xx,enemy_group[target].yy);
}
//--------------

void Tower::Reload_Tower()
{
    
reload+=1;
}

//=====================================================================

Ammo::Ammo (int xint yint nint t)
{
    
xx=x;
    
yy=y;
    
number=n;
    
target=t;
}

//-----------------------

void Ammo::Move_Ammoint j )
{
for(
int j=0j<ammoNj++)                       // Для каждого патрона из массива... Делать столько раз, сколько патронов в потоке.
    
{
        if ( 
enemy_group [target].xx == xx && enemy_group[target].yy == yy )
        {
            
enemy_group[target].health-=50;
        }
        else
        {
            
xx-=1;   // Движение по оси Х

            //Разница между высотой врага и патрона=высота патрона - высота"выделенного" врага
            
raznica_ammo_enemy_Y=0;
            if (
enemy_group[target].yy yy//Если высота врага < высота патрона
            
{
                
raznica_ammo_enemy_Y enemy_group[target].yy yy;
                if (
raznica_ammo_enemy_Y 5)
                {
                    
yy += raznica_ammo_enemy_Y;
                }
                else
                {
                    
yy += 5//Опускаемся на 5
                
}
            }
            else
            {
                
raznica_ammo_enemy_Y yy enemy_group[target].yy;
                if (
raznica_ammo_enemy_Y<5)
                {
                    
yy -= raznica_ammo_enemy_Y;
                }
                else
                {
                    
yy -= 5//Поднимаемся на 5
                
}
            }
        }
    }
}

//--------------------------
void Ammo::Spawn_Ammo int j )
{
    if ( 
tower_group[j].target >= && tower_group[j].target )           //Если у башни есть цель
    
{
        if (
enemy_group[tower_group[j].target].health>0)
        {
                
Ammo newAmmo (tower_group[j].xxtower_group[j].yyammoNtower_group[j].target);
                
ammo_group.push_backnewAmmo );
                
ammoN++;
                
tower_group[j].reload=0;   //Обнуляем для нового отсчета
        
}
    }
}
//-----------------

void Ammo::Draw_Ammo()
{
    
Form1->Canvas->Drawxxyyammo);
}
//===========================

void __fastcall TForm1::Button1Click(TObject *Sender)
{
for (
int i=0enemyNi++)
{
    
Enemy newEnemyrandom(100),random(300), 100 );
    
enemy_group.push_backnewEnemy );
}
Timer1->Enabled true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
for (
int i=0i<enemyNi++)
{
enemy_group[i].Move_Enemy();
}
//
if (tower_group.empty()!=true)
{
    for (
int i=0i<tower_group.size(); i++)
    {
    
tower_group[i].Zahvat_Target(); //Башни ищут ближайшую цель
    
}
    for(
int j=0j<nj++)
    {
        if (
tower_group[j].reload==10)
        {
            
ammo_group[j].Spawn_Ammo);
        }
        else
        {
            
tower_group[j].Reload_Tower();
        }
    }
    for (
int k=0k<ammoNk++)
    {
    
ammo_group[k].Move_Ammo);  //Двигаем все патроны
    
}
}
Invalidate();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormPaint(TObject *Sender)
{
for (
int i=0i<enemyNi++)
{
enemy_group[i].Draw_Enemy();
}

if (
tower_group.empty()!=true)
{
    for (
int i=0i<tower_group.size(); i++)
    {
        
tower_group[i].Draw_Tower();
        if ( 
tower_group[i].target >= )           //Если у башни есть цель то рисуем "лазер"
        
{
            if (
enemy_group[tower_group[i].target].health>0)
            {
              
tower_group[i].Draw_Lazer();
            }
        }
    }
    for(
int j=0ammoNj++)
    {
        
ammo_group[j].Draw_Ammo();
    }
}
Form1->Canvas->Draw(610235main);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
DoubleBuffered=true;
for (
int i=0enemyNi++)
{
    
Enemy newEnemyrandom(100),random(300), 100 );
    
enemy_group.push_backnewEnemy );
}
n=0;
mainX=610;
mainY=235;
ammoN=0;
tower = new Graphics::TBitmap;
tower->LoadFromFile("tower.bmp");
main = new Graphics::TBitmap;
main->LoadFromFile("main.bmp");
enemy2 = new Graphics::TBitmap;
enemy2->LoadFromFile("enemy2.bmp");
ammo = new Graphics::TBitmap;
ammo->LoadFromFile("ammo.bmp");
boom = new Graphics::TBitmap;
boom->LoadFromFile("boom.bmp");
}
//---------------------------------------------------------------------------


void __fastcall TForm1::FormMouseDown(TObject *SenderTMouseButton Button,
      
TShiftState Shiftint Xint Y)
{
if (
build==true)
{
    
Tower newTower X,Y10050, -110);
    
tower_group.push_backnewTower );
    
n++;
}
Invalidate();
Form1->Edit1->Text=tower_group.size();
}
//---------------------------------------------------------------------------


void __fastcall TForm1::Button2Click(TObject *Sender)
{
 if (
build==true){
build=false;
}
else {
build=true;}
}
//--------------------------------------------------------------------------- 

Оформление:
 
1) Бросается в глаза разный стиль именования переменных: mainX, mainY, raznica_ammo_enemy_Y. Нотация везде должна быть единой, даже если эта нотация - венгерская.
2) Конструктор класса Tower вынесен за его пределы - это ладно (хотя и не ясно, зачем), но почему он записан где-то в середине файла, а не сразу вслед за классом? А ещё лучше - выносить классы в отдельные файлы.
3) Да и что значат его переменные, почему они все однобуквенны? В строке Tower ( int x, int y, int h, int d, int t, int r) разобраться сможет только автор этого кода, и никто другой. А писать код надо так, будто сопровождать его будет склонный к насилию психопат - который знает, где ты живёшь. (с)
4) За названия вроде "raznica_ammo_enemy_Y" или "Zahvat_Target()" нужно вырвать и застрелить руки. Если уж не знаешь полностью английского (что вполне простительно) - то пиши всё транслитом, но смешивать языки - это моветон.
5) Все символы, относящие к названию типа, нужно писать слитно. В строке vector <Enemy> у тебя Enemy является частью типа, поэтому пробел ставить не надо. Это же касается и звёздочек в объявлениях указателей.
6) А вот в строках типа enemy_group[i].xx!=mainX, наоборот, нужно обязательно отделять пробелом знаки операций. Иначе визуально ничего не понятно. Арифметические операции - это полноценные функции, и они заслуживают "отделения".
7) Скобки {} кое-где поплыли, а кое-где и отступы вместе с ними. Местами вообще получилась нечитабельная каша, как в функции Zahvat_Target().


Кодинг:
 
1) Строка #include <vector> должна стоять выше, чем #pragma hdrstop. Потому как в твоём случае <vector> будет инклудиться всегда, хотя достаточно всего одного раза.
2) Используется множество глобальных переменных - которые, как известно, не есть гут. В большинстве случаев их можно заменить локальными, если только это не синглтоны. Да и хотя бы прокомментировать их не мешало бы.
3) Из-за конструкций вроде Form1->Canvas->Draw(610, 235, main) есть риск быть похороненным в закрытом гробу бирюзового цвета. Почему именно бирюзового? Потому что 610. А если уж эта строка нужна чисто "для дебага", то нужен комментарий об этом (а ещё лучше - условная компиляция).
4) В конструкторах лучше использовать списки инициализации, а не поочерёдное присваивание. Во-первых, так безопаснее. Во-вторых, только так можно проинициализировать не-статические константы класса.
5) Кстати, а где константы-то? В коде хватает переменных, которые не изменяются после инициализации. А ведь "константность" защищает от ошибок на этапе исполнения.
6) Раздражают конструкции вида if (tower_group.empty()!=true) или reload+=1. В первом случае сравнение с true можно не писать, а во втором нужен обычный инкремент.
7) Приведение типов в стиле C, как в строке (TColor)RGB(200,0,0), не всегда безопасно - лучше использовать "плюсовые" static_cast и dynamic_cast.
8) Зачем в функцию Move_Ammo( int j ) передаётся параметр j, когда он же вводится в первой строчке самой функции? Либо неиспользуемая переменная, либо просто ошибка.
9) Ввело в ступор содержимое функции Button2Click(). Надеюсь, что это просто "заглушка" такая?


Рекомендации:
 
1) Использовать везде единый стиль записи. Это касается именования переменных, расстановки скобок и комментариев. Имена должны быть осмысленными.
2) Упаковывать данные внутрь классов, используя идиому RAII. Если картинка относится к элементу конкретного класса, не надо таскать её как глобальную переменную - нужно выделить память под неё в конструкторе, и освободить в деструкторе.
3) Почему не стоит обходить вектор через int-переменную, скромно умолчу. Но на всякий случай посоветую почитать про итераторы. Через них всё идёт намного быстрее.
4) Вместо "голых" указателей лучше использовать shared_ptr<> и создавать всё в стеке, избегая кучи вообще. Хотя тебе ещё далековато до такой техники.
5) Вместо множества функций типа Draw_Tower() и Draw_Lazer() лучше иметь одну перегруженную функцию Draw(), которая могла бы принимать объекты разных типов. Это удобно для вызова функций (IDE сама показывает перегрузки), да и наследоваться от таких классов куда проще.
6) В любом классе желательно наличие конструктора по умолчанию (без параметров), дабы его объекты можно было использовать внутри массивов и STL-контейнеров. У тебя же далеко не везде так.

P.S. Только не стоит расстраиваться от прочитанного - я в твоём возрасте кодил намного хуже Rolleyes
(04.07.2012 19:44)Efrit Wrote: [ -> ]9) Ввело в ступор содержимое функции Button2Click(). Надеюсь, что это просто "заглушка" такая?

Функция меняет параметр build с true на false и наоборот. Что непонятного?
А в остальном почти во всём присоединяюсь.
Image: 6db876e06533.jpg

Оформление (Click to View)
Кодинг (Click to View)
рекомендации (Click to View)
Я эти ваши C++ не знаю, но ведь метод Draw_Enemy проходит по всем врагам и рисует их, но помимо этого он вызывается для каждого врага, не?

Quote:Я эти ваши C++ не знаю, но ведь метод Draw_Enemy проходит по всем врагам и рисует их, но помимо этого он вызывается для каждого врага, не?
Угу, это фейл.

Но к счастью это ни на что не влияет, кроме как зря рисует, зато четче будет)))
packa Wrote:Единой и старался делать) в 3 переменной просто необходимо такое название, иначе не ясно разница между чем и чем.
Не, я про другое. Я про символы подчёркивания в именах. Их надо либо использовать везде, либо вообще не использовать.

packa Wrote:У меня все конструкторы вынесены ниже, рядом с методами. Почему в середине? Просто у меня еще 2 класса, группировал контруктор+метод+метод+...
Нет, функции-члены класса должны распаолагаться либо внутри него, либо сразу вслед за ним. Я не хочу рыскать по всему cpp-шнику в поисках нужной мне функции - особенно, если самих классов много.

packa Wrote:Исключительно для конструктора. Если заглянуть в сам конструктор там все предельно ясно
Ничего не ясно. В строке Tower ( int x, int y, int h, int d, int t, int r) - что такое x? Что такое h? Что такое d, t, r? Если я захочу создать экземпляр твоего класса - то я не смогу этого сделать, поскольку я понятия не имею, что же значат его параметры. Правильно писать Tower (int x_pos, int y_pos, int health, int damage, int target, int reload). Поскольку иначе мне придётся копаться во внунренностях твоего класса, а мне некогда.

packa Wrote:Не понял что не так) КоординатаХ, КоординатаУ, картинка - вроде так все пишется.
Почему именно 610 и 235, а не 510 и 234? С какого перепугу функция меняет конкретные пиксели экрана? А что, если я захочу уменьшить размеры окна? Или у меня экран 480*320? А если это число 610 используется в нескольких функциях, а я захотел его поменять, что тогда? Мне придётся править каждую функцию, что ли?
Запомни: вообще нельзя использовать какие-то конкретные числа внутри кода. В худшем случае - такие константы надо дефайнить, и внутри функций использовать именно константы, а не явно указанные числа. Единственные числа, которые можно указывать явно - это 0, 1 и -1 (ну и двойка также иногда разрешается). Разве что, ещё можно использовать 8 как число бит в байте, 10 и 16 для функций перевода в системы счисления, ну и 100 для подсчёта процентов. Не более!

packa Wrote:Ammo::Ammo (int x, int y, int n, int t) : xx(x), yy(y), number(n), target(t); // ?
Да, именно так.

packa Wrote:Одна есть и хватит)) А если серьезно - специально оставлял переменные - чтобы при надобности просто их менять, не правя при этом код.
Константы сильно экономят время, отлавливая ошибки ещё на этапе компиляции. Когда-нибудь ты это оценишь.

packa Wrote:Со вторым полностью согласен, а вот с первым нет. Потому что код явно теряет свою очевидность, что тупо мешает читаемости. Я бы сказал что здесь овчинка выделки не стоит)
Какое из двух высказываний для тебя звучит более понятно?
   1) Если группа башен пуста, то...
   2) Если верно, что группа башен пуста, то...
На мой взгляд - однозначно первое... Вот и с кодом то же самое. Особенно если условий много, и они вложены друг в друга.

packa Wrote:Нажали на кнопку - Вошли в режим строительства - каждый клик строит башню.
Нажали повторно, вышли из режима, можем кликать до посинения, ничего не произойдет
Део верно заметил, что можно просто написать build = !build и не мучаться.

packa Wrote:Мозгу нуба намного сподручнее пользоваться интами, чем абстрактными итераторами)
Кстати уже заюзал в одном месте, но все равно тяжко обрабатывать мозгу, как это работает, хоть и понятно достаточно.
Итератор - это просто "обёртка" над указателем. Если ты не до конца понимаешь адресную арифметику указателей - то, конечно, итераторами пользоваться ещё не стоит.

packa Wrote:Почему? 3 класса = 3 конструктора.
Дык это не конструкторы по умолчанию - у них параметры есть! Я же говорил именно про конструкторы по умолчанию...

P.S. Да, ещё забыл сказать: public-переменные в классе - это почти всегда плохо. Нужно везде использовать get- и set-функции для каждой переменной, к которой планируется "сторонний" доступ. Даже если они будут простейшими.
Давайте я тут что ли спрошу. Дело в том что я заядлый дндшник и жутко устал тратить кучу сил и времени на генерацию персонажа, заполнение чарников, которые постоянно забываются и т.д. и т.п. Посему мне хочется это дело автоматизировать, но основная проблема заключается в том, что я слабо представляю какое этому всему придать внутреннее устройство. ну то есть я конечно могу зафигачить один такой большой map и обращаться к параметрам по строке-названию. после чего написать 9к строк кода с кучами свичей, а после того как захочу подкорректировать что-нибудь, благополучно стать погребённым в этом коде. У кого-нибудь есть идеи как мне помочь/что полистать/о чём размыслить
/кто виноват/что делать
?
Чубайс / трясти надо

Сложно ответить, поскольку я не знаю, что именно из себя представляют ДнД-шные чарники.
Можешь кинуть ссылки на описание, а ещё лучше - скрины/фотки заполненных листов?

И что там может поменяться, разве правила не фиксированы?
Посмотрел чарлисты и чуток глянул правила. Да уж, объёмистая штука!

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

Плюс, хватает "божественных объектов" типа класса или расы: если у персонажа изменить расу/класс, то у него вообще всё поменяется нафиг. Более того - насколько я понимаю, класс зависит от расы. И персонажи могут приобретать какие-то новые фичи в зависимости от комбинации раса+класс... Короче гря, полный набор антипаттернов Ab

Но уж твой вариант с "огромным map-ом" точно не прокатит - запутаешься с всевозможными хитросплетениями "божественных" параметров персонажа типа расы/класса/пола. Я бы советовал прежде всего выделить те классы, которые вообще никак не меняются: например, "слоты персонажа" вроде бы фиксированы (или же, у каких-то рас есть третья рука?). И в первую очередь - реализовать их.

Из-за того, что всё сильно связано - очень советую юзать property, иначе замучаешься. То есть либо юзай С#, либо (если хочется именно на плюсах) VC++ или Qt (второе лучше, так как кроссплатформ). Кроме этого, не советую юзать где-либо внутри классов поле "родитель" - это только ещё больше запутает код, поскольку вдобавок ко всему придётся помнить, чем является такое-то заклинание: врождённой фичей персонажа, или же свойством оружия...

Какие-то конкретные методы проектирования мне в голову не лезут. Хотя, той же "абстрактной фабрикой" здесь можно попробовать воспользоваться - поскольку изменение расы/класса/пола не ведут к добавлению каких-то абсолютно новых классов, а лишь к модификации свойств старых. Но сами фабрики получатся огромные - хз, стоит ли здесь овчинка выделки. Но это в любом случае куда лучше, чем сотни map-овских ключей, ещё и без пропертей 118

P.S. Кстати, я для своей ФРПГ (Аредита) чарлисты полностью автоматизировал, а заодно с ними и проведение битв тоже, но мне было куда легче - у меня есть "модульность" на уровне системы. Например, у моих персонажей нет классов вообще, а пол почти ни на что не влияет - то есть хоть какую-то иерархию классов (программных) построить можно... А вот как быть с ДнД, я толком не знаю - слишком её система уж громоздка.
Бывает и 3 руки. у меня с паттернами вообще говоря практически шапочное знакомство, я никогда реально их не использовал пока что. Мне тоже в голову пришла фабрика но я только боюсь как бы с ней не запутаться. про третью руку - и такое бывает, а вот 6 базовых параметров практически на 100% незыблемы. ладно, спасибо за помощь, пойду строить фабрику
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Reference URL's