2013-09-11 7 views
1

Я хочу создать абстрактный класс, который имеет чистую виртуальную функцию, которая вызывается конструктором, который НЕ является чисто виртуальным. Ниже мой файл class.hpp:абстрактные классы C++ с использованием чистых виртуальных функций в не чистых виртуальных функциях

#ifndef __CLASS_HPP__ 
#define __CLASS_HPP__ 

#include <iostream> 

class Parent { 
public: 
    Parent(){ 
    helloWorld(); // forced to say hello when constructor called      
    }; 
    virtual void helloWorld() = 0; // no standard hello...        
}; 

class Child : public Parent { 
public: 
    void helloWorld(){ // childs implementation of helloWorld       
    std::cout << "Hello, World!\n"; 
    }; 
}; 

#endif 

В этом примере, у меня есть родительский класс, который имеет чисто виртуальную функцию helloWorld(). Я хочу, чтобы каждый производный класс говорил «привет» при вызове конструктора; поэтому почему helloWorld() находится в конструкторе родительского класса. Тем не менее, я хочу, чтобы каждый производный класс был FORCED, чтобы выбрать, как он идет, скажите «привет», вместо того, чтобы использовать метод по умолчанию. Это возможно? Если я попытаюсь скомпилировать это с помощью g ++, я получаю ошибку, вызываемую конструктором чистой виртуальной функцией. Мой main.cpp является:

#include "class.hpp" 

int main(){ 
    Child c; 
    return 0; 
} 

Я компиляции с помощью g++ main.cpp -o main.out и результирующая ошибка:

In file included from main.cpp:1:0: 
class.hpp: In constructor ‘Parent::Parent()’: 
class.hpp:9:16: warning: pure virtual ‘virtual void Parent::helloWorld()’ called from constructor [enabled by default] 

Любые предложения о том, как получить подобную установку законным путем?

НОВОГО ВОПРОС

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

+0

Вызов виртуальной функции из CTOR (одного и того же объекта) опасно, потому что Безразлично» t вызывает переопределение из производных классов. В этом случае он пытается вызвать «Parent :: helloWorld», который является чистым, поэтому * warning * (чистая виртуальная функция все еще может иметь реализацию). Вы можете передать строку из производного класса в базовый класс ctor через параметр и сделать вывод в базовом классе. Также возможно: двухэтапный init. – dyp

+0

Кажется странным, что базовый класс зависит от производного класса, подобного этому. Можете ли вы рассказать о проблеме, которую пытаетесь решить? В зависимости от деталей могут быть доступны другие варианты. –

+0

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

ответ

1

Почему бы вам просто не добавить его к конструктору каждого дочернего класса?

Если вы хотите, чтобы избежать написания его каждый раз в конструкторе (или даже пропуск или унаследовать его), то вы можете использовать CRTP:

class Parent { 
public: 
    Parent(){}; 
    virtual void helloWorld() = 0; // no standard hello...        
}; 

template <typename Par> 
class ParentCRTP: public Parent { 
public: 
    ParentCRTP(){ 
    Par::doHelloWorld(); 
    }; 
    virtual void helloWorld(){ 
    Par::doHelloWorld(); 
    } 
}; 

class Child : public ParentCRTP<Child> { 
public: 
    static void doHelloWorld(){ // childs implementation of helloWorld       
    std::cout << "Hello, World!\n"; 
    }; 
}; 

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

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

2

Что вы делаете, является незаконным.

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

virtual void helloWorld() = 0; 

В этом случае вы правы.

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

Так,

Parent(){ 
helloWorld(); // forced to say hello when constructor called      
}; 

это является незаконным.

Если вы хотите, вы можете реализовать вашу чистую виртуальную функцию в производном классе, а затем вызвать helloWorld() из конструктора производного класса

+0

Это было бы не то, что я хотел. Я хочу, чтобы каждый дочерний класс был вынужден вызвать 'helloWorld()'. Код, который я пишу, будет использоваться другими, и я хочу, чтобы они были вынуждены вызвать эту функцию. – nick

+0

Я понял. Вот почему вы вызываете «helloWorld()» внутри конструктора родительского класса. Но дело в том, что если вы хотите определить абстрактный класс, он должен содержать хотя бы одну чистую виртуальную функцию. В вашем случае это «helloWorld()», и он не имеет реализации на уровне родительского класса. – ANjaNA

+0

@ ты не поняла? – ANjaNA

Смежные вопросы