LINUX.ORG.RU

C++ override методов.

 


1

2

Вот что-то я не смог осилить такую простую вещь как переопределение методов при наследовании.

#include <iostream>

class foo
{
  public:
    virtual void print() { std::cout << "foo\n";}
};


class bar : public foo
{
  public:
    void print() override { std::cout << "bar\n";} 
};


void fun(foo f)
{
  f.print();
}

int main()
{
  foo f;
  bar b;

  f.print();
  b.print();

std::cout << "===========\n";
  fun(b);

  return 0;
}

Вот по всем моим понятиям он после горизонтальной черты должен написать bar, a пишет foo :-(

Почему он так со мной, и что я делаю не так?

Мне то как раз надо чтобы позвали метод наследника, раз его передали в качестве параметров…

★★★

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

rumgot ★★★★★
()
Последнее исправление: rumgot (всего исправлений: 2)
Ответ на: Всем спасибо! от shaplov

Век живи,

С-сука, ты учебник хотя бы до середины дочитай. Это можно сделать за несколько часов.

А потом живи себе веками, не засоряя интернеты свой тупизной.

LamerOk ★★★★★
()
Ответ на: комментарий от rumgot

@fsb4000, @rumgot

а как быть в случае когда у нас такая переменная оказывается свойством объекта?

class SomeClass
{
    GenericProperty property;
    SomeClass(GenericProperty &pr) {property = pr}
}

class GenericProperty
{
 ....
}

class CustomProperty : public GenericProperty
{
 ....
}

Как сделать так, чтобы при вызове

    CustomPorperty cp;
    SomeClass sc(cp);

В свойстве property объекта cp были виртуальные методы от класса CustomPorperty?

shaplov ★★★
() автор топика
Последнее исправление: shaplov (всего исправлений: 1)
Ответ на: комментарий от shaplov

Точно также: храни ссылку или указатель на переменную.

#include <iostream>

using namespace std;

class GenericProperty {
   public:
    virtual void f() { cout << "GenericProperty::f()" << endl; }
};

class CustomProperty : public GenericProperty {
   public:
    virtual void f() override { cout << "CustomProperty::f()" << endl; }
};

class SomeClass {
   public:
    GenericProperty& property;
    SomeClass(GenericProperty& pr) : property(pr) {}
    void call() { property.f(); }
};

int main() {
    CustomProperty p;
    SomeClass s(p);
    s.call();
}


rumgot ★★★★★
()
Ответ на: комментарий от shaplov

или так через умный указатель:

#include <iostream>
#include <memory>

using namespace std;

class GenericProperty {
   public:
    virtual void f() { cout << "GenericProperty::f()" << endl; }
};

class CustomProperty : public GenericProperty {
   public:
    virtual void f() override { cout << "CustomProperty::f()" << endl; }
};

class SomeClass {
   public:
    shared_ptr<GenericProperty> property;
    SomeClass(GenericProperty* pr) : property(pr) {}
    void call() { property->f(); }
};

int main() {
    auto p = new CustomProperty;
    SomeClass s(p);
    s.call();
}

rumgot ★★★★★
()

Небольшой оффтоп

Вот когда у нас эта вся виртуальность и полиморфизм начинаются, то сразу делаем в базовом классе декструктор или виртуальный, или protected. Ну тут последствия - вследствие этого отваливаются move конструктор и move оператор =. Может данных в базовом классе нет, и заморачиваться не надо, но если есть, то нужно ручками дописывать. Вообще я скостылил макрос, который разворачивается нужный набор default/delete’эд методов, которые реализуют нужную политику. Вроде такого:

#define ONLY_MOVE(Name)               \
   Name(Name&&) = default;            \
   Name &operator=(Name&&) = default;
#define ONLY_COPY ...
#define COPY_MOVE ...
#define NO_COPY_MOVE ...

class foo
{
public:
    COPY_MOVE(foo);
    std::vector<int> v;
    virtual void print();
protected:
    ~foo() = default;
};

Т.е. один COPY_MOVE макрос скрыл сразу 4 декларации, удобно. Может есть какие-то более стандартные способы, о которых я не знаю? Потому что выглядит немного недоработанным со стороны языка, по-хорошему должны быть какие-то стандартные «макросы» для этого, а не мои костыли. Планируют ли что-то в стандарт завозить для этого?

pavlick ★★
()
Ответ на: комментарий от anonymous

Ну такая порнография не лучше:

class foo
{
public:
    foo(const foo&) = default;
    foo(foo&&) = default;
    foo &operator=(const foo&) = default;
    foo &operator=(foo&&) = default;
    std::vector<int> v;
    virtual void print();
protected:
    ~foo() = default;
};

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

pavlick ★★
()
Ответ на: комментарий от pavlick

порнография

дефенсиф программинг всегда порнография

anonymous
()
Ответ на: комментарий от pavlick

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

rumgot ★★★★★
()
1 июня 2021 г.

Статический анализ в помощь изучения языка

Кстати, это тот случай, когда использование статического анализа может помочь в понимании каких-то вопросов при изучении программирования. Анализаторы часто мыслят более высокоуровневыми сущностями, чем компиляторы. Поэтому могут подсказать про такие ошибки, как опечатка или заметить паттерн неверного написания кода из-за незнания какие-то нюансов языка.

Например, здесь PVS-Studio скажет: V1054 Object slicing. Derived class instance was passed by value to the function accepting base class instance. - https://godbolt.org/z/z8rrn4YzT

Далее можно пойти почитать, что такое V1054 и разобраться в вопросе: https://pvs-studio.com/ru/docs/warnings/v1054/

Andrey_Karpov_2020
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.