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

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

class parent {
      public:

      int b;
      void A(){
             //1. Throws exception if b < # ONLY when child1 calls
             //2. Always executes code if child2 calls regardless of condition
      }              
}           


class child1 : public parent {
}

class child2 : public parent {
}


int main(){

    child1 one;
    child2 two;

    one.A();        //This needs to throw exception under certain conditions
    two.A();        //This will always execute
}

У кого-нибудь есть советы, как определить, какой дочерний класс вызывает функцию?

1
Laurim 2 Апр 2014 в 22:57

4 ответа

Лучший ответ

Поскольку у вас нет виртуальных функций в базовом классе, вам просто не повезло. В противном случае вы могли бы получить typeid фактического класса, используя: typeid *this

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

1
Deduplicator 2 Апр 2014 в 19:10

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

class Child1 : public Parent
{
   void A(int v) 
   {
      if (this->b > v)
      {
         throw 1;
      }
      else
      {
         Parent::A(v);
      }
      return;
   }
}

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

class Parent
{
   virtual void A() =0;
}

class Child1 : public Parent
{
   void A(int v) 
   {
      if (this->b > v)
      {
         throw 1;
      }
      else
      {
         <<do something>>
      }
      return;
   }
}

В качестве альтернативы вы можете использовать функторы, но они могут быть очень сложными и потребовать C ++ 11. Ознакомьтесь с ними здесь: http://www.cprogramming.com/ учебник / функторы-функции-объекты-на-c ++. html

2
muppetjones 3 Апр 2014 в 19:47

Если вы не хотите использовать RTIA. Один из часто используемых шаблонов состоит в том, чтобы перечислить классы, которые называются «typeid», и дать каждой функции метод, который возвращает typeid объектов. Это позволит вам узнать, над каким типом вы сейчас работаете (путем вызова this-> typeid)

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

//override
return_type MyClass::MyFunction(ArgType arg)
{
    if ( !condidtionsMet ) {
        throw SomeException;
    } 
    else {
        return MyParentClass::MyFunction(arg);
    }

}
1
UpAndAdam 2 Апр 2014 в 19:10

Вы можете попробовать использовать dynamic_cast

void A(){
   if(dynamic_cast<child1>() == 0) {
         //1. Throws exception if b < # ONLY when child1 calls
   }
   else             
        //2. Always executes code if child2 calls regardless of condition
   }  
}

Но это плохая практика, гораздо лучше создать виртуальную функцию A () и переопределить ее для child1 и child2.

class parent {
      public:

      int b;
      virtual void A() = 0;
      virtual ~parent() {}

}           


class child1 : public parent {
    virtual void A() {
    }
}

class child2 : public parent {
    virtual void A() {
    }
}


int main(){

    child1 one;
    child2 two;

    one.A();        //This needs to throw exception under certain conditions
    two.A();        //This will always execute
}
0
Sandro 2 Апр 2014 в 19:08