|
|
|
|
Hello,
Je suis perplexe. J'ai codé un programme où j'ai une classe abstraite générique, pour laquelle je ne veux pas définir de constructeur par défaut. L'idée est d'en dériver plusieurs classes filles qui en implémentent les fonctions de différentes manières. J'ai donc écrit ça :
template <typename T>
class Analyseur {
private:
Analyseur(){std::cout << "plop !!!" << std::endl;}
public:
Echantillon<T> *analyse(Echantillon<double> *fft) = 0;
};
template <typename T>
class Analyseur_Copie : public Analyseur<T> {
// Je voudrais définir ici un constucteur et surcharger analyse()
};
Problème : Dans le programme de test que j'ai écrit, la ligne "Analyseur A()" ne semble pas poser de problèmes à mon compilateur, il fait ... quelque chose, je ne sais pas quoi. En tout cas à l'exécution, je ne vois aucun "plop !!!" s'afficher, ce qui tendrait à prouver que le constructeur par défaut que j'ai écrit n'a pas été utilisé ...
D'où ma question, qui peut se résumer en trois lettres : wtf !?
Ou bien, de façon plus détaillée, en trois points :
* Pourquoi puis-je instancier une classe abstraite ? Y a-t-il un rapport avec la généricité ?
* Pourquoi puis-je instancier une classe avec un constructeur par défaut non visible ?
* Qu'est-ce que fait le programme quand il "crée" une instance de Analyseur exactement ?
Salut.
|
Alors en effet, ce n'est pas "Analyseur A()" mais bien "Analyseur<double> A()" que j'ai mis dans mon programme et qui compilait.
|
Pour moi, ta class Analyseur est vide : elle est abstraite et ne contient aucune donnée membre. Il n'y a pas besoin d'un constructeur pour avoir une instance.
|
A priori en C++ il faut implémenter un constructeur par défaut si celui-ci est explicitement appelé (par exemple les containers de la STL l'appellent explicitement).
#include <iostream>
template <typename T>
class mere_t{
public:
mere_t(){
std::cout << "je suis ta mère !" << std::endl;
}
};
template <typename T>
class fille_t : public mere_t<T>{
public:
fille_t():mere_t<T>(){
std::cout << "nooooon !" << std::endl;
}
};
int main(){
fille_t<int> f;
return 0;
}
Donne : je suis ta mère ! nooooon ! Je te rappelle aussi que les membres de classes pouvant être initialisés avant l'accolade ouvrante du constructeur doivent l'être, et ce conformément à l'ordre dans lequels ils sont déclarés. AInsi : class plop_t{
protected:
int i; // d'abord i
char c; // ensuite c
float f; // enfin f
public:
plop_t(int i0=0,float f0,char c0='x'):
i(i0),c(c0),f(f0) // d'abord i, ensuite , enfin f
{
// code du constructeur (éventuellement vide)
}
};
Bonne chance |
Il me semble que le constructeur par défaut est créé automatiquement si aucun constructeur n'est fourni au compilateur, un peu comme operator= et le destructeur qui sont définis automatiquement.
class A{
A(){};
int a;
}
struct B :public A{
B(){}; //ou B():A(){};
int b;
}
int main()
{
A a; // erreur appel direct à un constructeur privé
B b; // erreur aussi, B fesant appel au constructeur privé A()
return 0;
}
Salutation ! avant je croyais, maintenant je suis fixé.Jésus Christ
Char Snipeur |
Il me semble que le constructeur par défaut est créé automatiquement si aucun constructeur n'est fourni au compilateur
(mando@aldur) (~) $ cat plop.cpp
class plop_t{
protected:
unsigned x;
public:
plop_t(unsigned x0):x(x0){}
};
int main(){
plop_t p = plop_t();
return 0;
}
(mando@aldur) (~) $ g++ -W -Wall plop.cpp
plop.cpp: In function ‘int main()’:
plop.cpp:9: error: no matching function for call to ‘plop_t::plop_t()’
plop.cpp:5: note: candidates are: plop_t::plop_t(unsigned int)
plop.cpp:1: note: plop_t::plop_t(const plop_t&)
plop.cpp:9: warning: unused variable ‘p’
(mando@aldur) (~) $ g++ --version
g++ (GCC) 4.2.4 (Debian 4.2.4-1)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
De plus l'appel aux constructeur(s) mère(s) n'est a priori pas fait par défaut (cf message <1>) |