C параметры по умолчанию

порядок:

  1. Основной конструктор
  2. Конструктор порожденного класса
  3. Полученный деструктор
  4. Основной деструктор

Пример:

class B
{
public:
  B()
  {  
    cout<<"Construct B"<<endl;
  }

  virtual ~B()
  {
    cout<<"Destruct B"<<endl;
  }
};

class D : public B
{
public:
  D()
  {  
    cout<<"Construct D"<<endl;
  }

  virtual ~D()
  {
    cout<<"Destruct D"<<endl;
  }
};



int main(int argc, char **argv)
{
  D d; 
  return 0;
}

Вывод примера:

D

Конструкции B

Конструкции Разрушает D

, Разрушают B

Несколько уровней работ наследования как стек:

, Если Вы рассматриваете продвижение объекта на стек как конструкция и взлетание это как разрушение, тогда можно посмотреть на несколько уровней наследования как стек.

Это работает на любое количество уровней.

Пример, который D2 получает из D, происходит из B.

Нажатие B на стеке, продвиньте D на стеке, продвиньте D2 на стеке. Таким образом, порядок конструкции является B, D, D2. Затем для обнаружения порядка разрушения начинают появляться. D2, D, B

более сложные примеры:

Для более сложных примеров, см. ссылку, предоставленную @JaredPar

258
задан Wolf 7 May 2019 в 23:02
поделиться

13 ответов

Не совсем. Единственный способ - написать функцию varargs и вручную ввести значения по умолчанию для аргументов, которые вызывающий абонент не передает.

133
ответ дан 23 November 2019 в 02:39
поделиться

Yes you can do somthing simulair, here you have to know the different argument lists you can get but you have the same function to handle then all.

typedef enum { my_input_set1 = 0, my_input_set2, my_input_set3} INPUT_SET;

typedef struct{
    INPUT_SET type;
    char* text;
} input_set1;

typedef struct{
    INPUT_SET type;
    char* text;
    int var;
} input_set2;

typedef struct{
    INPUT_SET type;
    int text;
} input_set3;

typedef union
{
    INPUT_SET type;
    input_set1 set1;
    input_set2 set2;
    input_set3 set3;
} MY_INPUT;

void my_func(MY_INPUT input)
{
    switch(input.type)
    {
        case my_input_set1:
        break;
        case my_input_set2:
        break;
        case my_input_set3:
        break;
        default:
        // unknown input
        break;
    }
}
0
ответ дан 23 November 2019 в 02:39
поделиться

Обычно нет, но в gcc вы можете сделать последний параметр funcA () необязательным с помощью макроса.

В funcB () я использую специальное значение (-1), чтобы указать, что мне нужно значение по умолчанию для параметра 'b'.

#include <stdio.h> 

int funcA( int a, int b, ... ){ return a+b; }
#define funcA( a, ... ) funcA( a, ##__VA_ARGS__, 8 ) 


int funcB( int a, int b ){
  if( b == -1 ) b = 8;
  return a+b;
}

int main(void){
  printf("funcA(1,2): %i\n", funcA(1,2) );
  printf("funcA(1):   %i\n", funcA(1)   );

  printf("funcB(1, 2): %i\n", funcB(1, 2) );
  printf("funcB(1,-1): %i\n", funcB(1,-1) );
}
3
ответ дан 23 November 2019 в 02:39
поделиться

Нет, но вы можете рассмотреть возможность использования набора функций (или макросов) для аппроксимации с использованием аргументов по умолчанию:

// No default args
int foo3(int a, int b, int c)
{
    return ...;
}

// Default 3rd arg
int foo2(int a, int b)
{
    return foo3(a, b, 0);  // default c
}

// Default 2nd and 3rd args
int foo1(int a)
{
    return foo3(a, 1, 0);  // default b and c
}
4
ответ дан 23 November 2019 в 02:39
поделиться

Да. :-) Но не так, как вы ожидаете.

int f1(int arg1, double arg2, char* name, char *opt);

int f2(int arg1, double arg2, char* name)
{
  return f1(arg1, arg2, name, "Some option");
}

К сожалению, C не позволяет вам перегружать методы, так что вы получите две разные функции. Тем не менее, вызывая f2, вы фактически вызываете f1 со значением по умолчанию. Это решение «Не повторяйся», которое помогает избежать копирования / вставки существующего кода.

152
ответ дан 23 November 2019 в 02:39
поделиться

Вероятно, лучший способ сделать это (что может или не может быть возможным в вашем случае в зависимости от вашей ситуации) - это перейти на C ++ и использовать его как «лучший C». Вы можете использовать C ++ без использования классов, шаблонов, перегрузки операторов или других дополнительных функций.

Это даст вам вариант C с перегрузкой функций и параметрами по умолчанию (и любыми другими функциями, которые вы выбрали для использования). Вам просто нужно быть немного дисциплинированным, если вы действительно серьезно относитесь к использованию только ограниченного подмножества C ++.

Многие люди скажут, что использовать C ++ таким образом - ужасная идея, и они могут быть правы. Но это всего лишь мнение; Я считаю, что использовать возможности C ++, которые вам удобны, можно, не вкладываясь во все это.

13
ответ дан 23 November 2019 в 02:39
поделиться

Еще одна опция использует struct s:

struct func_opts {
  int    arg1;
  char * arg2;
  int    arg3;
};

void func(int arg, struct func_opts *opts)
{
    int arg1 = 0, arg3 = 0;
    char *arg2 = "Default";
    if(opts)
      {
        if(opts->arg1)
            arg1 = opts->arg1;
        if(opts->arg2)
            arg2 = opts->arg2;
        if(opts->arg3)
            arg3 = opts->arg3;
      }
    // do stuff
}

// call with defaults
func(3, NULL);

// also call with defaults
struct func_opts opts = {0};
func(3, &opts);

// set some arguments
opts.arg3 = 3;
opts.arg2 = "Yes";
func(3, &opts);
13
ответ дан 23 November 2019 в 02:39
поделиться

Нет.

9
ответ дан 23 November 2019 в 02:39
поделиться

Вероятно, проблема заключается в удаленном характере ваших вызовов.

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

Если вы не имеете дело со сценарием надстройки (а это не так), внедрение метода не является правильным решением. Вы почти уже поняли это, поскольку считаете неудовлетворительным то, что вам нужно вызывать его вручную, потому что ваш контейнер DI не может.

Если я полностью не ошибаюсь, ContactController не нуждается в экземпляре IValidationDictionary перед его методами действия вызываются?

Если это так, то, вероятно, самым простым решением было бы определить интерфейс IValidationDictionaryFactory и заставить конструктор ContactController использовать экземпляр этого интерфейса.

Этот интерфейс можно определить следующим образом:

public interface IValidationDictionaryFactory
{
    IValidationDictionary Create(Controller controller);
}

Любой Затем метод действия на контроллере, которому требуется экземпляр IValidationDictionary, может вызвать метод Create для получения экземпляра.

18
ответ дан 23 November 2019 в 02:39
поделиться

Краткий ответ: Нет.

Чуть более длинный ответ: Существует старый, старый обходной путь, при котором вы передаете строку, которую вы parse для необязательных аргументов:

int f(int arg1, double arg2, char* name, char *opt);

где opt может включать пару «name = value» или что-то в этом роде, и который вы бы назвали как

n = f(2,3.0,"foo","plot=yes save=no");

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


Вы все еще находите этот подход в кодах физики элементарных частиц, которые написаны профессиональными программами на C ++ (например, ROOT ). Его главное преимущество состоит в том, что его можно расширять практически на неопределенный срок, сохраняя при этом обратную совместимость.

13
ответ дан 23 November 2019 в 02:39
поделиться

Нет.

Даже самый последний стандарт C99 не поддерживает это.

19
ответ дан 23 November 2019 в 02:39
поделиться

Ого, все здесь такие пессимисты. Ответ - да.

Это не тривиально: к концу у нас будет основная функция, вспомогательная структура, функция-обертка и макрос вокруг функции-обертки. В моей работе у меня есть набор макросов для автоматизации всего этого; как только вы поймете последовательность действий, вам будет легко сделать то же самое.

Я уже писал об этом в другом месте, поэтому вот подробная внешняя ссылка, дополняющая краткое изложение здесь: http://modelingwithdata.org/arch/00000022.htm

Мы хотим превратить

double f(int i, double x)

в функцию, которая принимает значения по умолчанию (i=8, x=3.14). Определите сопутствующую структуру:

typedef struct {
    int i;
    double x;
} f_args;

Переименуйте вашу функцию f_base, и определите функцию-обертку, которая устанавливает значения по умолчанию и вызывает базу:

double var_f(f_args in){
    int i_out = in.i ? in.i : 8;
    double x_out = in.x ? in.x : 3.14;
    return f_base(i_out, x_out);
}

Теперь добавьте макрос, используя вариативные макросы языка Си. Таким образом, пользователи не должны знать, что они f_args struct и думать, что они делают обычное дело:

#define f(...) var_f((f_args){__VA_ARGS__});

Хорошо, теперь все следующее будет работать:

f(3, 8);      //i=3, x=8
f(.i=1, 2.3); //i=1, x=2.3
f(2);         //i=2, x=3.14
f(.x=9.2);    //i=8, x=9.2

Проверьте правила о том, как составные инициализаторы устанавливают значения по умолчанию, чтобы узнать точные правила.

Одна вещь не будет работать: f(0), потому что мы не можем отличить отсутствующее значение от нулем. По моему опыту, с этим нужно быть осторожным, но об этом можно позаботиться, когда в половине случаев по умолчанию действительно будет ноль.

Я потрудился написать это, потому что считаю, что именованные аргументы и значения по умолчанию действительно делают кодирование на C проще и даже веселее. И Си - потрясающий язык, потому что он настолько прост, но при этом в нем достаточно всего, чтобы сделать все это возможным.

260
ответ дан 23 November 2019 в 02:39
поделиться

Да, с функциями C99 вы можете это сделать. Это работает без определения новых структур данных или около того и без того, чтобы функция решала во время выполнения, как она была вызвана, и без каких-либо вычислительных затрат.

Подробное объяснение см. В моем сообщении на

http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/

Йенс

4
ответ дан 23 November 2019 в 02:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: