2013-10-09 3 views
1

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

Но это не работает должным образом. Вот минимальный тест я написал:

template<typename T> 
class A { 
    public: 
    void f(T& foo) { } 
}; 

class B : public A<int> { 
    public: 
    template<typename T> 
    void f(T& foo) { } 
}; 

int main() { 
    A<int>* ptr = new B; 
    ptr->f("foo"); 
    delete ptr; 
    return 0; 
} 

Конечно, это не работает:

[email protected]:~/Workspace/Test/src$ icpc -o Test Test.cpp 
Test.cpp(16): error: a reference of type "int &" (not const-qualified) cannot 
be initialized with a value of type "const char [4]" 
    ptr->f("foo"); 
     ^

compilation aborted for Test.cpp (code 2) 

Есть ли способ заставить компилятор использовать определение метода из класса B, или это действительно Плохая идея?

-

Редактировать: Сделано наследство общественности.

ответ

3

Прежде всего, как отметил @GermanDiago, вы используете частное наследование, поэтому получаете ошибку «недопустимый базовый класс». Измените B на A<int> публично.

Несмотря на это, это не решит проблему. Поиск имени основан на статических типах. Когда у вас есть указатель на A<int>, доступ к элементам через этот указатель будет рассматривать только члены A<int>.

Вы должны получить доступ через типа B, чтобы увидеть членов B «s:

int main() { 
    B* ptr = new B; 
    ptr->f("foo"); 
    delete ptr; 
    return 0; 
} 

Конечно, если я правильно понимаю ваш вопрос, это не то, что вы действительно хотите. Вместо этого вы можете посмотреть на Curiously Recurring Template Pattern.

template <class T, class Derived> 
class A { 
    public: 
    template <class U> 
    void f(U& bar) { 
     static_cast<Derived*>(this)->f(bar); 
    } 

    void f(T& foo) { 

    } 
}; 


class B : public A<int, B> 
{ 
    public: 
    template <class T> 
    void f(T &foo) { 
     //will be called from A's f(U&) 
    } 
}; 


int main() { 
    A<int, B>* ptr = new B; 
    ptr->f("foo"); 
    delete ptr; 
    return 0; 
} 

Live example

Конечно, это имеет недостаток в B становится частью типа A «s. Я не думаю, что есть выход из этого, оставаясь при этом компиляцией.

+0

Спасибо за полезное объяснение. Очевидно, мне придется подумать еще немного ... – Pierre

1

Вы должны использовать открытое наследование:

class B : public A<int> { 
    //... 
} 

это-связь в С ++ через публичное наследование. Частное наследование - это то, что вы сейчас используете.

+0

Верно, но это все равно не позволит вызывать 'B :: f' с помощью указателя на' A'. – Angew

+0

Спасибо. Простая ошибка, которую я только что исправил. Все еще не устраняет основную проблему:/ – Pierre

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