Rechercher : dans
Par :

[C++] Instanciation d1 classe abstraite oO !?

Dernière réponse le 4 jun 2008 à 14:20:38 Sir Bedevere, le 3 jun 2008 à 10:59:54 
 Signaler ce message aux modérateurs

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 ?

Meilleures réponses pour « [C++] Instanciation d1 classe abstraite oO !? » dans :
Classe abstraite et fonction virtuelle pure Voir Classe abstraite et fonction virtuelle pure Dans l’exemple de code 7.3(fonctions virtuelles), la classe Noeud a ceci de particulier qu’elle représente uniquement un concept. Elle a été définie pour isoler les caractéristiques générales des...
Le mot-clé static ou les attributs et méthodes de classe en POO Voir(NOTE: Cet article explique la signification du mot-clé static au sein d'une classe. La signification de "static" en C n'a par exemple rien à voir.) Vous êtes débutant en programmation orientée objet. En Java, en C++...ou que sais-je encore,...
Introduction à la STL en C++ (standard template library) VoirIntroduction Principales classes de la STL std::pair std::list std::vector std::set std::map Les iterators iterator et const_iterator reverse_iterator et const_reverse_iterator Les algorithmes ...
Les templates en C++ VoirIntroduction Avantages Inconvénients Quand utiliser des templates ? Que dois-je mettre dans les .hpp et dans les .cpp ? Convention de notations Quelques templates célèbres STL BGL Premiers pas Spécifications de templates Template par...
Les classes en langage C++ VoirLa notion d'objet Le langage C est un langage procédural, c'est-à-dire que c'est un langage permettant de définir des données grâce à des variables, et des traitements grâce aux fonctions. L'apport principal du langage C++ par rapport au...
UML - Modélisation des classes et objets VoirModélisation d'un objet La modélisation objet consiste à créer une représentation abstraite, sous forme d'objets, d'entités ayant une existence matérielle (arbre, personne, téléphone, ...) ou bien virtuelle (sécurité sociale, compte bancaire,...
Adresse IP VoirSommaire Qu'est-ce qu'une adresse IP Déchiffrement d'une adresse IP Adresses particulières Les classes de réseaux (obsolète) Classe A Classe B Classe C Attribution des adresses IP Adresses IP réservées Masques de sous-réseau Interet...

1

Char Snipeur, le 3 jun 2008 à 11:42:00

Salut.
En effet, je suis perplexe aussi.
Que se passe t il si tu essai d'utliser A ? A.analyse(...)
Je ne comprends même pas pourquoi il compile.
si Analyseur<double> A(); fonctionne, il y a vraiment un problème. Quel est le compilateur ? Salutation ! avant je croyais, maintenant je suis fixé.Jésus Christ
Char Snipeur

Répondre à Char Snipeur

2

Sir Bedevere, le 3 jun 2008 à 14:44:37

Alors en effet, ce n'est pas "Analyseur A()" mais bien "Analyseur<double> A()" que j'ai mis dans mon programme et qui compilait.

Je viens de voir aussi que je n'avais pas mis le mot-clé "virtual" devant la déclaration d'analyse(). Une fois rajouté ce mot-clé, le compilo (c'est g++ 4.2 au fait) jette bien une erreur parce que j'essaie d'instanciser une classe abstraite. ouf !

Toutefois, l'instanciation d'une classe dérivée avec le constructeur par défaut fonctionne toujours, et je ne comprends pas pourquoi.

Répondre à Sir Bedevere

3

Char Snipeur, le 3 jun 2008 à 15:22:01

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.
En lisant un cour d'assembleur, il parlai justement des notions de structure et de classe en C/C++.
Un structure (ou classe) est interprété par le compilateur comme une espèce de tableau avec des membres de taille variable. Les fonctions membre d'une classe, sont en fait des fonctions classiques avec un argument cacher :
type classA::fct(a,b) <=> type fct(classA&,a,b)
Donc, une class ne contenant que des fonctions, ne prend pas d'espace mémoire (enfin, c'est une image) donc n'a pas besoin de constructeur.
Mais ce n'est que mon avis, il faudrait vérifier dans les spécifications de l'ISO C++ et ne pas oublié que tout compilateur s'écarte un peu de ces spécifications, en particulier sur ces problèmes assez marginaux. Salutation ! avant je croyais, maintenant je suis fixé.Jésus Christ
Char Snipeur

Répondre à Char Snipeur

4

mamiemando, le 3 jun 2008 à 16:10:04

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).

De plus ce constructeur doit explicitement appeler les constructeurs des classes mères (ceci différencie le C++ du java, mais c'est grâce à ce genre de chose qu'on peut faire du multi-héritage en C++).

Exemple :

#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

Répondre à mamiemando

5

Char Snipeur, le 3 jun 2008 à 16:34:27

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.
Par contre, dès que l'on défini un constructeur, le constructeur par défaut (sans argument) doit être défini explicitement si on veux qu'il soit utilisable.
Le problème de Bedevere (je pense) c'est qu'il définit un constructeur par défaut privé et que cela ne crée pas d'erreur lors de la déclaration de la variable. Un constructeur privé empêche la déclaration d'un objet.
Pour s'en convaincre, le code suivant compiler avec gcc 3.2.3 :

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

Répondre à Char Snipeur

6

mamiemando, le 3 jun 2008 à 20:29:01

Il me semble que le constructeur par défaut est créé automatiquement si aucun constructeur n'est fourni au compilateur

Oui mais non. A priori il faut partir du principe qu'il n'y a pas de constructeur par défaut construit automatiquement (contrairement à = ou au destructeur).

(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>)

Répondre à mamiemando

7

Char Snipeur, le 4 jun 2008 à 08:30:17

C'est bien ce que je disais "si aucun autre constructeur n'est défini", là tu défini plop_t(uint).
Et d'ailleurs, on vois lors de la compilation que ça ne concerne pas le constructeur par copie. Salutation ! avant je croyais, maintenant je suis fixé.Jésus Christ
Char Snipeur

Répondre à Char Snipeur

8

 mamiemando, le 4 jun 2008 à 14:20:38

Ok

Répondre à mamiemando
Collection CommentÇaMarche.net