Какой объект производного класса вызвал невиртуальную функцию в базовом классе

Справочная информация:

У меня есть базовый класс Base, который имеет в основном «чистые» виртуальные функции и некоторые невиртуальные функции (плюс пара виртуальных функций).

По сути, общие функции всех производных классов Derived, Derived2 и т. Д. Представлены в базовом классе как невиртуальные функции.

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

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

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

Минимальный рабочий пример: Вот минимальный рабочий пример. Я урезал его насколько возможно.

#include <iostream>


#include <pthread.h>
#include <string>
#include <errno.h>
#include <cstring>

class Base {
public:
    Base() {}
    virtual ~Base() {}
    int waitForThreadToExit() {
        int error = pthread_join(m_Thread, NULL);
        if (0 != error) {
            std::cerr << "Error from pthread_join(). errorCode:" << strerror(errno) << std::endl;
        }
        return error;
    }

    int start() {
        if ((startThread()) != 0) {
             std::cerr << "error returned from the start() function." << std::endl;
         }
    }

protected:
    virtual int runThread(void) {
      std::cout << "Reimplement" << std::endl;;
      return -1;
    }
    int startThread() {
        int error = pthread_create(&m_Thread, NULL, internalThreadEntryFunc, this);
        return error;
    }

private:
    static void* internalThreadEntryFunc(void* This) {
        ((Base *) This)->runThread();
        return NULL;
    }
    pthread_t m_Thread;
};


class Derived: public Base {
public:
    Derived() {}
    virtual ~Derived() {}

private:
    virtual int runThread(void) {
        while(1) {
             std::cout << "Sehr gut!" << std::endl;;
             return 0;
        }
    }

};

class Derived2: public Base {
public:
    Derived2() {}
    virtual ~Derived2() {}

private:
    virtual int runThread(void) {
        while (1)
        {
            std::cout << "Sehr sehr gut!" << std::endl;;
            return 0;
        }
    }

};


int main()
{
    std::cout << "Hello World!" << std::endl;
    Derived d;
    Derived2 d2;
    d.start();
    d2.start();
    d.waitForThreadToExit();
    d2.waitForThreadToExit();
    return 0;
}

person Duck Dodgers    schedule 18.12.2018    source источник
comment
Распечатка этого сообщит вам тип. В Visual Studio тип объекта очевиден, как и для gdb.   -  person Matthieu Brucher    schedule 18.12.2018
comment
@MatthieuBrucher: О, быстро! верно! Я не думаю, что!   -  person Duck Dodgers    schedule 18.12.2018
comment
Вам, вероятно, следует присоединиться к ~Base(), если вы еще этого не сделали, когда это произойдет. Если у вас C ++ 11 или новее, возможно, стоит взглянуть на стандартную <thread> библиотеку. Он очень похож на pthread, но имеет более приятные (C ++) блокировки / мьютексы и т. Д.   -  person Ted Lyngmo    schedule 18.12.2018
comment
И в чем преимущество присоединения к деструктору базового класса? (p.s. У меня нет C ++ 11.)   -  person Duck Dodgers    schedule 18.12.2018
comment
@MatthieuBrucher, печать this действительно сообщает мне адрес указателя. Да, это способ (хотя и косвенный) узнать, какой из производных объектов называется функцией базового класса. Но в вашем комментарии есть вторая часть, которую я раньше не заметил. У меня есть gdb и eclipse, и я отлаживал и входил в функцию. Ни стек не дает мне такой информации, ни я нигде не вижу здесь тип объекта. Погуглив, я нашел эту ссылку Вы имеете в виду эту ptype команду в gdb?   -  person Duck Dodgers    schedule 18.12.2018
comment
Если базовый класс имеет виртуальную функцию, то typeid(*this) предоставит объект type_info наиболее производного типа. Таким образом, в gdb вы можете получить имя наиболее производного типа с помощью printf "%s\n",typeid(*this).__name или просто pring typeid(*this)   -  person Oliv    schedule 18.12.2018
comment
@Oliv, может быть, это эффект моего древнего компилятора, но я не могу получить доступ к __name. НО, я могу использовать name() функцию-член. У меня это работает, typeid(*this).name().   -  person Duck Dodgers    schedule 20.12.2018
comment
@joeyMallone Для меня наоборот, я не могу вызывать функции-члены. И я был бы признателен. Какой отладчик / компилятор вы используете? Я использую gcc / gdb v8.2.   -  person Oliv    schedule 20.12.2018
comment
@Oliv, я вынужден использовать gcc 4.4.5 с gdb 7.0.1. Может это и примечательно (или нет), но у меня glibc 2.11.3   -  person Duck Dodgers    schedule 21.12.2018


Ответы (1)


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

#include <iostream>
#include <typeinfo>

class base {
public:
    virtual const char* name() {
        return typeid(*this).name();
    }
    virtual ~base(){}
};

class derived : public base {};
class otherDerived : public base {};

int main () {
    base b;
    derived d;
    otherDerived d2;

    std::cout << "base says:" << b.name() << std::endl;
    std::cout << "derived says:" << d.name() << std::endl;
    std::cout << "other derived says:" << d2.name() << std::endl;
}

который дает результат при запуске в моем QtCreator:

base говорит: 4base
производное говорит: 7dervied
другое производное говорит: 12otherDerived

Примечание. Лучше всего создать виртуальную функцию name() или className() и вызывать эту функцию везде, вместо того, чтобы разбрасывать typeid(*this).name() повсюду в коде.

person Duck Dodgers    schedule 08.08.2019