C ++ наследование, базовые методы скрыты - PullRequest
5 голосов
/ 29 сентября 2010

У меня есть простой базовый класс C ++, пример производного класса.

// Base.hpp 
#pragma once

class Base
{
public:
    virtual float getData();
    virtual void setData(float a, float b);
    virtual void setData(float d);

protected:
    float data;
};

//Base.cpp
#include "stdafx.h"
#include "Base.hpp"

float Base::getData()
{ 
    return data; 
}

void Base::setData(float a, float b)
{ 
    setData(a);
}

void Base::setData(float d)
{ 
    data = d;
}

//Derived.hpp
#pragma once
#include "Base.hpp"

class Derived
    : public Base
{
public:
    virtual void setData(float d);
};

//Derived.cpp
#include "stdafx.h"
#include "Derived.hpp"

void Derived::setData(float d)
{
    data = d + 10.0f;
}

Если я сейчас сделаю указатель на Base, это прекрасно скомпилируется.

//Main.cpp
#include "stdafx.h"
#include "Base.hpp"
#include "Derived.hpp"

Base *obj = new Derived();

Но если я сделаюуказатель на класс Derived, затем компилятор (VC 2008 и 2010) жалуется, что:

Main.cpp(12): error C2660: 'Derived::setData' : function does not take 2 arguments

А вот код, который вызывает эту ошибку:

//Main.cpp
#include "stdafx.h"
#include "Base.hpp"
#include "Derived.hpp"

Derived *obj = new Derived();

Кажется, чтометоды базового класса скрыты.У меня сложилось впечатление, что поскольку методы базового класса являются виртуальными, они должны быть видны даже при просмотре с помощью указателя на производное, или я ошибаюсь?

Ответы [ 2 ]

11 голосов
/ 29 сентября 2010

Это артефакт поиска имени в C ++. Основной алгоритм заключается в том, что компилятор будет начинаться с типа текущего значения и подниматься по иерархии до тех пор, пока не найдет элемент типа, имеющий целевое имя. Затем будет выполнено разрешение перегрузки только для элементов этого типа с заданным именем. Он не учитывает членов с одинаковыми именами в родительских типах.

Способ обойти это - переопределить функции на Derived и просто переслать их до Base

class Derived {
  ...
  void setData(float a, float b);
}

void Derived::setData(float a, float b) {
  Base::setData(a,b);
}

Кроме того, вы можете ввести базовые элементы в область видимости, используя объявление using

class Derived {
  using Base::setData;
  ...
}

Документация по использованию

3 голосов
/ 29 сентября 2010

Функция в производном классе скрывает любую функцию с тем же именем в базовом классе.

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

class Base { 
public:
    void setData(float d);
    void setData(float d, float e);
};

class Derived : public Base { 

    using Base::setData;

    void SetData(float d);
};

[Пересмотрено:] Кажется, моя память была неправильной.Это не вызывает двусмысленности - даже с объявлением using, Derived::setData имеет приоритет (так сказать), поэтому при вызове setData(float) для производного объекта вы получите Derived::setData(float).Если вы сделаете его виртуальным и вызовете его через указатель на Base, вы все равно получите Derived::setData(float);.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...