как передать класс в метод, и из базового класса обнаружить наследника? - PullRequest
0 голосов
/ 16 декабря 2011

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

Вот пример того, что я хотел бы сделать:

#include <iostream>

class Base {

  public:
    int _type;
    Base() { }
};

class First : public Base {
  public:
    int _first_only;

    First() { }
};

class Second : public Base {
  public:
    int _second_only;

    Second() { }
};

void test (Base b) {

  std::cout << "Type: " << b._type << std::endl;

  if(b._type==1) {
    std::cout << "First\n";
    // Want to be able to do this
    std::cout << "Val: " << (First)b._first_only << std::endl; 
  } else if(b._type==2) {
    std::cout << "Second\n";
    // And this
    std::cout << "Val: " << (Second)b._second_only << std::endl;
  }
}

int main() {

  First f;
  f._first_only=1;
  f._type=1;
  Second s;
  s._type=2;
  s._second_only=2;

  test(f);
  test(s);
}

Ответы [ 4 ]

1 голос
/ 16 декабря 2011

Это похоже на ответы других:

  1. Вы можете написать полиморфные классы, чтобы получить это поведение, используя виртуальные функции.
  2. Передавать объекты класса Dervied либо по указателю, либо по ссылке наполучить полиморфное поведение.В противном случае это приведет к нарезке объектов.Ваша функция test () приводит к нарезке объектов.

Этот код также может вам помочь.Вы можете видеть, что есть разные способы напечатать тип.Я использовал GetBaseType (), GetDerivedType () и GetType ().Среди этих методов GetType () удобный для вас случай.Для удобства есть два конструктора.Конструкторы позволяют инициализировать элементы данных.

class Base {
private:
    int _type;
public:
    Base(int type) : _type(type) { }
    int GetBaseType() { return _type; }
    virtual int GetDerivedType() = 0;
    virtual int GetType() { return _type; }
};

class First : public Base {
private:
    int _first_only;
public:
    First() : Base(1), _first_only(1) { }
    First(int first_only) : Base(first_only), _first_only(first_only) { }
    int GetDerivedType() { return _first_only; }
    virtual int GetType() { return _first_only; }
};

class Second : public Base {
private:
    int _second_only;
public:
    Second() : Base(2), _second_only(2) { }
    Second(int second_only) : Base(second_only), _second_only(second_only) { }
    int GetDerivedType() { return _second_only; }
    virtual int GetType() { return _second_only; }
};

void test (Base &b) {
    std::cout << "Type: " << b.GetBaseType() << std::endl;
    std::cout << "Type: " << b.Base::GetType() << std::endl;

    std::cout << "Dervied type: \n";
    std::cout << "Val: " << b.GetDerivedType() << std::endl; 
    std::cout << "Val: " << b.GetType() << std::endl; 
}

int main() {

  First f(1);
  Second s(2);

  test(f);
  test(s);

  First f1;
  Second s1;

  test(f1);
  test(s1);
}
1 голос
/ 16 декабря 2011

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

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

1 голос
/ 16 декабря 2011
  1. Либо объявите функцию virtual в Base
  2. Переместите общие типы элементов из First и Second в Base.

Для вашей конкретной задачи лучше выбрать 2-й вариант:

class Base {
  public:
    int _member;  // have getter() method, if '_member' is private
    Base() { }
};

Внутри test():

void test (Base &b) {  // <--- practice to pass by reference if copy is not needed
  // use b._member;
};
0 голосов
/ 16 декабря 2011

Три вещи, которые я бы сделал:

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

Вот как будет выглядеть код:

#include <iostream>

class Base {

  public:
     int _type;
     Base() { }
     virtual void print_to_stream( std::ostream & os ) const =0;
};

class First : public Base {
  public:
    int _first_only;

    First() {  _type =1; }
    void print_to_stream( std::ostream & os ) const
    {
       os<<"First\n";
       os<<"Val: " << _first_only << std::endl;
    }
};

class Second : public Base {
  public:
    int _second_only;

    Second() { _type=2; }

    void print_to_stream( std::ostream & os ) const
    {
      os << "Second\n";
      os << "Val: " << _second_only << std::endl;
    }
};

void test (Base & b)
{
  std::cout << "Type: " << b._type << std::endl;
  b.print_to_stream( std::cout );
}

int main() {
  First f;
  f._first_only=1;
  Second s;
  s._second_only=2;

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