Je pense que cette déclaration reflète la confusion ici (l'emphase est mienne):
Je ne comprends pas qu'est-ce qui est requis dans une classe pour être admissible à être une base de clas (pas un polymorphes une)?
Dans idiomatiques C++, il y a deux utilisations pour dériver à partir d'une classe:
-
privé de l'héritage, utilisé pour mixin et la programmation orientée aspects à l'aide de modèles.
-
public de l'héritage, utilisé pour polymorphes situations seulement. EDIT: Ok, je suppose que cela pourrait être utilisé dans quelques mixin scénarios, tels que l'
boost::iterator_facade
-- qui se présentent lorsque le PROGRAMME est en cours d'utilisation.
Il n'y a absolument aucune raison de faire publiquement dériver une classe en C++ si vous êtes pas d'essayer de faire quelque chose polymorphes. La langue dispose d'une connexion fonctionne comme une caractéristique standard de la langue, et des fonctions libres sont ce que vous devriez être en utilisant ici.
Pensez-y de cette façon -- voulez-vous vraiment à forcer les clients de votre code afin de le convertir à l'aide de certains propriétaires classe string tout simplement parce que vous voulez ajouter un peu de méthodes? Parce que, contrairement à Java ou C# (ou les plus similaires langages orientés objet), lorsque vous dérivez une classe en C++, la plupart des utilisateurs de la classe de base besoin de savoir sur ce genre de changement. En Java/C#, les classes sont généralement accessibles par le biais de références, qui sont similaires à C++les pointeurs. Donc, il y a un niveau d'indirection qui découple les clients de votre classe, vous permettant de remplacer une classe dérivée sans les autres clients le savoir.
Toutefois, en C++, les classes sont des types de valeur , contrairement à la plupart des autres langages à objets. La meilleure façon de voir ce qui est connu comme le découpage de problème. Fondamentalement, pensez à:
int StringToNumber(std::string copyMeByValue)
{
std::istringstream converter(copyMeByValue);
int result;
if (converter >> result)
{
return result;
}
throw std::logic_error("That is not a number.");
}
Si vous passer votre propre chaîne à cette méthode, le constructeur de copie pour std::string
seront appelés à en faire une copie, pas le constructeur de copie pour votre objet dérivé -- n'importe quel enfant de la classe d' std::string
est passé. Cela peut conduire à une incohérence entre vos méthodes et de tout ce qui est fixé à la chaîne. La fonction StringToNumber
ne peut pas simplement prendre quel que soit votre objet dérivé est et de la copie, tout simplement parce que votre objet dérivé probablement a une taille différente de celle d'un std::string
- , mais cette fonction a été compilée à la réserve seulement de l'espace pour un std::string
de stockage automatique. En Java et C# ce n'est pas un problème parce que la seule chose comme stockage automatique impliqués sont des types référence, et les références sont toujours de la même taille. Pas le cas en C++.
Longue histoire courte, ne pas utiliser l'héritage pour virer de bord sur les méthodes en C++. Ce n'est pas idiomatiques et les résultats dans des problèmes avec la langue. L'utilisation non-ami, non des fonctions de membre si possible, suivie de la composition. Ne pas utiliser l'héritage, sauf si vous êtes modèle de la métaprogrammation ou souhaitez le comportement polymorphique. Pour plus d'informations, voir Scott Meyers Effective C++ Article 23: Préférer la non-membre non-ami de fonctions de fonctions membres.
EDIT: Voici un exemple plus complet montrant le découpage de problème. Vous pouvez voir qu'elle est sortie sur codepad.org
#include <ostream>
#include <iomanip>
struct Base
{
int aMemberForASize;
Base() { std::cout << "Constructing a base." << std::endl; }
Base(const Base&) { std::cout << "Copying a base." << std::endl; }
~Base() { std::cout << "Destroying a base." << std::endl; }
};
struct Derived : public Base
{
int aMemberThatMakesMeBiggerThanBase;
Derived() { std::cout << "Constructing a derived." << std::endl; }
Derived(const Derived&) : Base() { std::cout << "Copying a derived." << std::endl; }
~Derived() { std::cout << "Destroying a derived." << std::endl; }
};
int SomeThirdPartyMethod(Base /* SomeBase */)
{
return 42;
}
int main()
{
Derived derivedObject;
{
//Scope to show the copy behavior of copying a derived.
Derived aCopy(derivedObject);
}
SomeThirdPartyMethod(derivedObject);
}