0
votes

Supprimer conditionnellement le membre de classe au moment de l'exécution ou ignorer l'appel du constructeur de cet objet membre

// globally accessible variable. can be changed at runtime.
bool feature_flag = true

Class A
{
  std::conditional <feature_flag, UtilityClass, DummyClass> obj_util;

  A(int x,int y,int z)
  {
  }
}

6 commentaires

Peut-être avez-vous besoin de vérifier à l'exécution dans le constructeur par défaut UtilityClass , pour que cela fonctionnera toujours?


Comme je l'ai mentionné dans mon article, je ne peux pas toucher UtilityClass. Merci


Si les deux seules options possibles que vous avez (en utilisant des pointeurs et en modifiant la classe) ne peuvent pas être faites (pour des «raisons») alors vous êtes à court d'options. Et à mon avis pas humble du tout, si le UtilityClass dépend du feature_flag , il aurait dû être conçu et implémenté pour s'assurer qu'il n'échoue pas lors de l'exécution- temps à cause du drapeau, quelle que soit sa valeur.


Il semble que vous ayez un problème de conception. Vous devez peut-être diviser A en une base (sans les fonctionnalités supplémentaires optionnelles) et une sous-classe (qui les ajoute).


@TobySpeight merci. C'est une solution que j'ai en tête.


@Someprogrammerdude convient qu'il s'agit d'un problème de conception que quelqu'un a fait il y a 8 ans, et maintenant nous n'avons pas assez de ressources pour refactoriser ceci :-(


3 Réponses :


-1
votes

De quoi s'agit-il de stocker un pointeur vers UtitlityClass au lieu de la classe elle-même. Préférez un unique_ptr . Ensuite, si votre drapeau est vrai, créez la classe, sinon vous avez nullptr. Lorsque vous utilisez la classe, vous devez effectuer des vérifications de nullptr.

Class A
{
public:
  A(int x,int y,int z)
  {
      if( feature_flag == true ){
          // obj_util.reset( new UtilityClass() ); //c++11
          // since c++14
          obj_util = std::make_unique< UtilityClass >();
      }

      // can be anywhere int class
      if( obj_util != nullptr ){
          obj_util->doStuff();
      } 
  }
private:
  std::unique_ptr<UtilityClass> obj_util = nullptr;


}


4 commentaires

L'auteur avait mentionné qu'il ne pouvait pas utiliser le pointeur dans ce projet


Oops. Oui, vous avez raison. Mais avec les informations dont nous disposons, je pense toujours que c'est une solution viable.


préférez utiliser std :: make_unique lors de l'initialisation std :: unique_ptr <...> objet


Oui bien sûr. Mais comme je suis coincé avec un compilateur C ++ 11, il n'y a pas de std :: make_unique. Je changerai la réponse



0
votes

Si vous ne voulez pas changer obj_util en pointeur, il serait peut-être raisonnable de le changer en fonction:

class AWrapper {
public:
    AWrapper(bool enabled) {
        if (enabled) ptr = std::make_unique<A>();
    }
    void print() { ptr->print(); }

private:
    std::unique_ptr<A> ptr;
};

bool feature_flag = true;

class B {
public:
    B() : obj_util(feature_flag) {
        if (feature_flag) {
            // No need to change the syntax
            obj_util.print();
        }
    }

private:
    AWrapper obj_util;
};

Une autre option consiste à créer une classe wrapper, qui réplique l'interface:

class A {
public:
    A() { std::cout << "Constructor"; }
    void print() { std::cout << "Print"; }
};

bool feature_flag = true;

class B {
public:
    B() : obj_util(feature_flag) {
        if (feature_flag) {
            obj_ptr = std::make_unique<A>();

            // Syntax has to be changed to a function call
            obj_util().print();
        }
    }

private:
    std::unique_ptr<A> obj_ptr;
    A& obj_util() const { return *obj_ptr; }

};


0 commentaires

2
votes

Vous pouvez utiliser quelque chose de similaire à conception basée sur des règles ici. J'implémenterais une classe qui stocke la UtilityClass basée sur la spécialisation de modèle d'un drapeau booléen:

auto foo() {

    A<true> t;
    auto& feature = t.utility; //compiles

    A<false> t2;
    auto& feature2 = t2.utility; // does not compile

}

Classe A code> peut activer cette fonctionnalité en fonction d'un booléen donné comme paramètre de modèle:

template<bool FeatureActivated>
struct A : public Feature<FeatureActivated> {};

Vous pouvez utiliser A comme ceci: p >

template<bool FeatureActivated> struct Feature;
template<> struct Feature<true> {
    UtilityClass utility;
};
template<> struct Feature<false> {};

Voici l'exemple complet: https://godbolt.org/ z / b3Kmo7

Modifier: Cela ne permet pas d'activer ou de désactiver la fonctionnalité pendant l'exécution.


1 commentaires

J'aime cette approche, car elle évite les pointeurs comme le PO le suggérait. Mais pour être juste, je pense que c'est une approche compliquée pour résoudre une tâche facile simplement parce que l'OP ne veut pas remplacer obj_util. par obj_util-> qui est une simple opération de remplacement . La taille de la base de code n'a donc pas d'importance. Il prétend également qu'il est sûr que obj_util ne sera pas appelé lorsque l'indicateur est faux, donc il pourrait même omettre les vérifications de nullptr (ce que je ne conseillerais pas). Avec une solution comme celle-ci, le code ne devient pas plus lisible car il introduit une complexité inutile. Néanmoins +1 pour l'idée.