Вызов производных классов с базовым значением аргумента по умолчанию, C ++ [duplicate]

Простейшее обходное решение, использующее None

>>> def bar(b, data=None):
...     data = data or []
...     data.append(b)
...     return data
... 
>>> bar(3)
[3]
>>> bar(3)
[3]
>>> bar(3)
[3]
>>> bar(3, [34])
[34, 3]
>>> bar(3, [34])
[34, 3]
33
задан Björn Pollex 24 June 2011 в 07:54
поделиться

6 ответов

По умолчанию аргументы полностью компилируются. То есть замещение аргументов по умолчанию вместо отсутствующих аргументов выполняется во время компиляции. По этой причине, очевидно, что выбор аргументов по умолчанию для функций-членов не может зависеть от типа dynamic (т.е. времени выполнения) объекта. Он всегда зависит от типа static (т.е. времени компиляции) объекта.

Вызов, который вы написали в своем примере кода, сразу интерпретируется компилятором как bp->print(10) независимо от чего-либо еще.

25
ответ дан AnT 21 August 2018 в 20:51
поделиться
  • 1
    Спасибо Андрею за то, что он уяснил мои сомнения. Я не думал в этом направлении. Большое спасибо. – paper.plane 24 June 2011 в 10:28

В стандарте говорится (8.3.6.10):

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

Это означает, что, поскольку вы вызываете print с помощью указателя типа B, он использует аргумент по умолчанию B::print.

31
ответ дан Björn Pollex 21 August 2018 в 20:51
поделиться
  • 1
    Fundoo отвечает, но помогает понять. благодаря – paper.plane 24 June 2011 в 10:29

Динамическое связывание использует vpointer и vtable. Однако динамическое связывание применяется только к указателю на функцию. Механизм динамического связывания отсутствует.

Таким образом, аргумент по умолчанию определяется статически во время компилятора. В этом случае он статически определяется типом bp, который является указателем на базовый класс. Таким образом, data = 10 передается как аргумент функции, а указатель функции указывает на функцию класса Derived: D :: print. По сути, он вызывает D :: print (10).

Следующий фрагмент кода и результирующие выходы четко демонстрируют точку: даже если он вызывает функцию члена Derived call Derived :: resize (int), это передает основной аргумент по умолчанию: size = 0.

virtual void Derived :: resize (int) size 0

#include <iostream>
#include <stdio.h>
using namespace std;

#define pr_dbgc(fmt,args...) \
    printf("%d %s " fmt "\n",__LINE__,__PRETTY_FUNCTION__, ##args);

class Base {
   public:
       virtual void resize(int size=0){
           pr_dbgc("size %d",size);
       }
};

class Derived : public Base {
   public:
       void resize(int size=3){
           pr_dbgc("size %d",size);
       }
};

int main()
{   
    Base * base_p = new Base;
    Derived * derived_p = new Derived;

    base_p->resize();           /* calling base member function   
                                   resize with default
                                   argument value --- size 0 */
    derived_p->resize();        /* calling derived member      
                                   function resize with default 
                                   argument default --- size 3 */

    base_p = derived_p;         /* dynamic binding using vpointer 
                                   and vtable */
                                /* however, this dynamic binding only
                                   applied to function pointer. 
                                   There is no mechanism to dynamic 
                                   binding argument. */
                                /* So, the default argument is determined
                                   statically by base_p type,
                                   which is pointer to base class. Thus
                                   size = 0 is passed as function 
                                   argument */

    base_p->resize();           /* polymorphism: calling derived class   
                                   member function 
                                   however with base member function  
                                   default value 0 --- size 0 */

     return 0;
}


 #if 0
 The following shows the outputs:
 17 virtual void Base::resize(int) size 0
 24 virtual void Derived::resize(int) size 3
 24 virtual void Derived::resize(int) size 0
 #endif
0
ответ дан Jason Xiong 21 August 2018 в 20:51
поделиться

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

#include <iostream>
void frob (int x) {
    std::cout << "frob(" << x << ")\n";
}

void frob (int = 0);
int main () {
    frob();                     // using 0
    {
        void frob (int x=5) ;
        frob();                 // using 5
    }
    {
        void frob (int x=-5) ;
        frob();                 // using -5
    }
}

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

3
ответ дан Sebastian Mach 21 August 2018 в 20:51
поделиться

Значение аргумента по умолчанию передается от имени вызывающего. С точки зрения вызывающего абонента он работает с классом B (не D), поэтому он пропускает 10 (как для класса B)

1
ответ дан user396672 21 August 2018 в 20:51
поделиться

ваша переменная имеет тип B, поэтому вызывается функция B. Чтобы позвонить D, вам нужно либо объявить свою переменную как D, либо записать в D.

0
ответ дан vsz 21 August 2018 в 20:51
поделиться
  • 1
    Поскольку функция члена print объявляется виртуальной, вызов через указатель базового класса вызовет производную версию функции-члена, а не базовую версию. – templatetypedef 29 June 2017 в 22:55
Другие вопросы по тегам:

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