Вызвать абстрактный метод в суперклассе и реализовать его в подклассе в C ++? - PullRequest
4 голосов
/ 14 февраля 2012

В Java можно написать абстрактный суперкласс с нереализованными абстрактными методами и неабстрактными методами, которые вызывают абстрактные методы.Затем в подклассе реализуются абстрактные методы.Когда вы затем создаете экземпляр подкласса, суперкласс использует реализации в подклассе.Как мне сделать это в C ++?

Вот что я имею в виду, но в Java:

SuperClass.java

public abstract class SuperClass {

    public SuperClass() {
        method();
    }

    private void method() {
        unimplementedMethod();
    }

    protected abstract void unimplementedMethod();
}

SubClass.java

public class SubClass extends SuperClass {

    public SubClass() {
        super();
    }

    @Override
    protected void unimplementedMethod() {
        System.out.println("print");
    }

    public static void main(String[] args) {
        new SubClass();
    }
}

Было бы здорово, если бы вы показали мне, как это делается в C ++.:)

Ответы [ 5 ]

4 голосов
/ 14 февраля 2012

В общем, то, что вы ищете, это ключевое слово virtual. В двух словах virtual заявляет, что этот метод может быть переопределен . Обратите внимание, что такой метод все еще может иметь реализацию - virtual просто делает его перезаписываемым. Чтобы объявить «абстрактный метод», вы можете сказать, объявлять намерение , предоставьте реализацию в производном классе с = 0, как показано ниже. Такие методы называются чисто виртуальными в C ++.

Однако есть некоторые предостережения, на которые вам следует обратить внимание. Как указано в комментарии ниже, вы вызывали method() из конструктора SuperClass. К сожалению, это невозможно в C ++ из-за порядка, в котором создаются объекты.

В C ++ конструктор производного класса сразу вызывает свой конструктор суперкласса, прежде чем размещать его члены или выполнять тело конструктора. Таким образом, члены базового класса конструируются первыми, а члены производного класса конструируются последними. Вызов виртуального метода из базового класса не будет работать так, как вы ожидаете в Java, поскольку производный класс еще не создан, и, таким образом, виртуальные методы еще не перенаправлены в производные реализации. Надеюсь, что это имеет смысл.

Однако вызов method() для SuperClass объекта после создания будет работать так, как вы ожидаете: он вызовет виртуальную функцию, которая выдаст «print».

class SuperClass {

public:
    SuperClass() {
        // cannot call virtual functions from base constructor.
    }
    virtual ~SuperClass() { } // destructor. as Kerrek mentions,
                               // classes that will be inherited from,
                               // should always have virtual destructors.
                               // This allows the destructors of derived classes
                               // to be called when the base is destroyed.

private:
    void method() {
        unimplementedMethod();
    }

protected:
    virtual void unimplementedMethod() = 0; // makes method pure virtual,
                                            // to be implemented in subclass
}

SubClass.h

class SubClass : public SuperClass {

public:
    SubClass() : SuperClass() { // how the superclass constructor is called.

    }

    // no need for "override" keyword, if the methd has the same name, it will
    // automatically override that method from the superclass
protected:
    void unimplementedMethod() { 
        std::cout << "print" << std::endl;
    }
}
3 голосов
/ 14 февраля 2012

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

class SuperClass
{
public:
    void action() { method(); }   // not in the constructor, please
    virtual ~SuperClass() { }     // always a virtual destructor when polymorphic

protected:
    void method() { unimplementedMethod(); }

private:
    virtual void unimplementedMethod() = 0;
};

class SubClass : public SuperClass
{
private:
    virtual void unimplementedMethod() { std::cout << "print" << std::endl; }

// no need to spell out the next couple of functions, but for your entertainment only
public:
    SubClass() : SuperClass() { }
    virtual ~SubClass() { }
};

Теперь для вызова:

int main()
{
    SuperClass * p = new SubClass; // construct first...
    p->action();                   // ... then invoke, after construction is complete

    delete p;                      // thank god for that virtual destructor!
}

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

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

(Пример использования немного надуманный, поскольку вы обычно не используете new или необработанные указатели в C ++.)

1 голос
/ 14 февраля 2012

Вам нужно использовать виртуальные методы.Реализация работает так:

/* here's MyBaseClass.h */
class MyBaseClass
{
public:
    MyBaseClass(void);
    ~MyBaseClass(void);

    void MyMethod();

protected:
    virtual void MyUnimplementedMethod() = 0;
};


/* here's MyIneritedClass.h */
class MyInheritedClass :
    public MyBaseClass
{
public:
    MyInheritedClass(void);
    ~MyInheritedClass(void);

protected:
    virtual void MyUnimplementedMethod();
};


/* here's the implementation of the method in the base class */
void MyBaseClass::MyMethod()
{
    MyUnimplementedMethod();
}


/* and here's the implementation of the abstract method in the derived */
void MyInheritedClass::MyUnimplementedMethod()
{
    _tprintf(L"Hello, world");
}
1 голос
/ 14 февраля 2012

В C ++ они называются чисто виртуальными функциями / методами.

Обычно вы ставите «= 0» в конце метода:

virtual doSomething() = 0; // pure virtual

Найдите в SO "c ++ pure virtual", и вы найдете множество ответов.

0 голосов
/ 14 февраля 2012

Вы объявляете метод как virtual:

сниппет:

class Parent{
public:
    virtual int methodA() {return methodB();}; // calls the abstract method
    virtual int methodB() = 0; // "=0" means pure virtual, not implemented in the base
}

class Child : public Parent{
public:
    virtual int methodB() { /* implementation */}
}

virtual означает, что дочерний объект может переопределить реализацию, и тогда родитель должен вызвать переопределенную реализацию. Добавление «= 0» к объявлению метода virtual делает его виртуальным pure , то есть база не имеет собственной реализации и полагается на реализацию дочерним элементом. Такой класс не может быть создан (т.е. абстрактный класс).

...