Indirection C ++ lors de l'accès aux membres d'un autre membre
-
28-10-2019 - |
Question
Compte tenu de l'exemple de code suivant:
class Room {
Room() : switch(*this) { }
Lamp lamp;
Switch switch;
void TurnOn() { lamp.TurnOn(); }
}
class Switch {
Switch(Room& room) : room(room) { }
Room& room;
void TurnOn() { room.lamp.TurnOn(); }
}
Je crois comprendre que le deuxième TurnOn()
implique un niveau supplémentaire d'indirection, car nous devons suivre la référence à room.Est-ce correct?Cette indirection supplémentaire sera-t-elle supprimée si l'appel peut être intégré (soit via une insertion explicite, soit via l'optimisation de l'ensemble du programme au niveau de l'éditeur de liens)?Ou, en d'autres termes, la fonction TurnOn de Switch pourrait-elle être accélérée en la remplaçant par:
class Room {
Lamp lamp;
Switch switch;
Room() : switch(*this,lamp) { }
void TurnOn() { lamp.TurnOn(); }
}
class Switch {
Room& room;
Lamp& lamp;
Switch(Room& room,Lamp& lamp) : room(room),lamp(lamp) { }
void TurnOn() { lamp.TurnOn(); }
}
Ou, plus généralement, si vous détenez une référence à un objet, y a-t-il un niveau d'indirection moins impliqué dans l'accès à ses membres directement via une référence plutôt que via la référence puis le membre?
Merci
La solution
Cela pourrait être plus rapide (mais pas beaucoup). Cependant, les deux exemples sont incorrects dans la mesure où ils interrompent l'encapsulation et violent la loi de Demeter . Ils exigent que la classe Switch
ou toute personne qui l'instancie ait accès à la fois au Room
lui-même et au Lamp
qu'il contient. Bien sûr, nous supposons également que chaque pièce a une lampe et qu'une lampe ne peut exister que dans une pièce ... ce qui signifie que si ces conditions changent, il y a deux classes à changer au lieu d'une seule.
Le premier exemple serait mieux écrit comme
class Room {
public:
Room() : sw(*this) { }
void TurnOn() { lamp.TurnOn(); }
private:
Lamp lamp;
Switch sw;
};
class Switch {
public:
Switch(Room& room) : room(room) { }
void TurnOn() { room.TurnOn(); }
private:
Room& room;
};
car alors le Room
est responsable de ce qui est activé. Cela pourrait être une lampe, une radio. Switch
n'a plus à s'en soucier. Ce sera probablement plus lent, mais c'est plus facile à gérer.
Si vous voulez exiger ce Switch
, activez uniquement un Lamp
, alors
class Room {
public:
Room() : sw(lamp) { }
void TurnOn() { lamp.TurnOn(); } // (semantics: who "turns on" a room?)
private:
Lamp lamp;
Switch sw;
};
class Switch {
public:
Switch(Lamp& lamp) : lamp(lamp) { }
void TurnOn() { lamp.TurnOn(); }
private:
Lamp& lamp;
};
Cela devrait être tout aussi rapide, sans exiger que nous interrompions l'encapsulation.
Autres conseils
Votre deuxième exemple ne sera (probablement) pas plus rapide que le premier exemple.Dans les deux cas, une référence doit être résolue avant que TurnOn()
puisse être invoqué.