Pregunta

C++ preguntas de principiante.Por favor, compruebe que estoy haciendo lo correcto.

Tengo una aplicación global de la clase de desove es a los niños y la necesito para dar a los niños el acceso a algunas de las instalaciones de aplicaciones.Así que me decidí a pasar a los niños por referencia.

He probado la idea como se muestra a continuación.Parece que funciona bien.Yo sólo quería asegurarme de que no estoy haciendo algo peligroso.Hay allí cualquier escollos que pasé por alto?

Padre crea a los niños y les da sus llaves del coche:

#include <iostream>
using namespace std;

class CCarKeys
{
    public:
        CCarKeys(const string& Name) : _Name(Name) {}
        string _Name;
};

class CChild
{
    public:
        CChild(CCarKeys& CarKeys) : _Name("Child"), _CarKeys(CarKeys) {}
        string _Name;
        CCarKeys& _CarKeys;
        void TestHasKeys() {cout << "I got " << _CarKeys._Name << endl;}
};

class CDad
{
    public:
        CDad() : _Name("Dad"), _HondaCarKeys("Honda keys"), _ChevyCarKeys("Chevy keys") {}
        string _Name;
        CCarKeys _HondaCarKeys;
        CCarKeys _ChevyCarKeys;
        CChild *_Boy;
        CChild *_Girl;
        void MakeBoy() {_Boy= new CChild(_HondaCarKeys);}
        void MakeGirl() {_Girl= new CChild(_ChevyCarKeys);}
};

int main ()
{
    CDad Dad;

    Dad.MakeBoy();
    Dad.MakeGirl();
    Dad._Boy->TestHasKeys();
    Dad._Girl->TestHasKeys();
}
¿Fue útil?

Solución

Se ve bien para mí (si las teclas es todo lo que necesitan).Pueden necesitar otros servicios de Papá que se solicita más adelante, como por ejemplo:

Wallet += MyDad.GasMoney(REQUEST_MAX_AND_PROMISE_TO_BE_HOME_BY_10PM) ;

Pero ellos no tienen una referencia a su Papá, por lo que no será capaz de hacer eso.Así me gustaría tener la CChild constructor de tomar una this de referencia, también.

class ICashProvider {
public:
  virtual money Request(IPerson,CashRequestFlags) ;
};

class IChaffeur {
public:
  virtual void Drive(IPerson[]) ;
};

etc.

Y, a continuación, CChild constructor deberá tomar ICashProvider y IChaffeur, como CWife y CGirlfriend (y CBoyfriend, tal vez).En este punto, creo que te dieras cuenta de que este nivel de granularidad es inútil en la cara de Dad's responsabilidades y que acaba de dar a todo el mundo this y han Dad autenticar las solicitudes, obligando a los que llaman a enviar a sus propios this en algunos métodos, por lo que no tiene Dad la realización de incesto o el cambio de la CWife's pañal.

Otros consejos

Pasar por referencia es lo mismo que pasar por puntero, excepto por la semántica y el hecho de que no puede hacer nada con el puntero en sí mismo si pasa por referencia.

Su código está bien.

En su caso particular, es probable que no se otorguen las llaves del automóvil de forma permanente, sino que se soliciten según sea necesario y se otorguen por solicitud. Entonces es más

class Dad
{
   /** may return NULL if no keys granted */
   CarKeys *requestKeys(CChild forChild);
}

En el caso más general de la clase de aplicación principal y los niños, ¿qué tal crear el objeto de datos compartido por la aplicación y los niños en main (), y pasar referencias a todos.

Es posible y en su código no está causando daño. Pero es peligroso, porque si copia CDad, se copiarán las teclas y los punteros. Sin embargo, los objetos a los que apuntarán los punteros y la referencia dentro de esos objetos seguirán siendo los mismos. Si el objeto CDad original queda fuera de alcance, las referencias en los objetos a los que hacen referencia los punteros están colgando, sin hacer referencia a ningún objeto válido.

Tal vez puedas revertir vidas: crea las claves en el montón y los niños como miembros normales dentro de la clase. Entonces, si copias a papá, los niños se copian, pero las claves no. Creo que las claves son inmutables, por lo que puede compartir la misma clave entre varios niños.

Esto lleva a otro punto: si sus claves son razonablemente pequeñas (léase: no enormes) e inmutables (por lo que no tiene anomalías de actualización si cambia una clave, pero no las otras), considere crearla no en el montón también, por lo que también se copian automáticamente y se los pasan a los niños cuando necesitan la clave. Puede convertirlos en punteros normales de los niños, pero creo que eso es feo, porque el niño no contiene una clave, sino que la usa. Por lo tanto, un puntero / referencia o un parámetro de función se ajusta bien, pero no un & "; Real &"; miembro de datos.

Si va con la clave compartida y las claves en el montón, debe usar punteros inteligentes, porque debe hacer un seguimiento de todos los niños y padres. Si el último niño / papá está fuera de alcance, debe eliminar la clave nuevamente. Utiliza boost::shared_ptr para eso:

class CCarKeys
{
    public:
        CCarKeys(const string& Name) : _Name(Name) {}
        string _Name;
};

class CChild
{
    public:
        CChild(boost::shared_ptr<CCarKeys> const& CarKeys) 
            : _Name("Child"), _CarKeys(CarKeys) {}
        string _Name;
        boost::shared_ptr<CCarKeys> _CarKeys;
        void TestHasKeys() {cout << "I got " << _CarKeys._Name << endl;}
};

class CDad
{
    public:
        // NOTE: null the kid pointers *if* you use raw pointers, so you can check whether
        // a boy or girl is present. Without nulling them explicitly, they have 
        // indeterminate values. Beware. shared_ptr's however will automatically
        // initialized to default "null" values
        CDad() : 
            _Name("Dad"), 
            _HondaCarKeys(new CCarKeys("Honda keys")), 
            _ChevyCarKeys(new CCarKeys("Chevy keys")) {}
        string _Name;

        boost::shared_ptr<CCarKeys> _HondaCarKeys;
        boost::shared_ptr<CCarKeys> _ChevyCarKeys;

        // also use shared_ptr for the kids. try to avoid raw pointers. 
        boost::shared_ptr<CChild> _Boy;
        boost::shared_otr<CChild> _Girl;

        void MakeBoy() {_Boy.reset(new CChild(_HondaCarKeys));}
        void MakeGirl() {_Girl.reset(new CChild(_ChevyCarKeys));}
};

// main can be used unchanged

Por supuesto, puede evitar toda esta complejidad simplemente haciendo que la clase CDad no sea copiable. Luego puede usar su solución original, simplemente haciendo que los niños usen shared_ptr y haciendo que los niños no se puedan copiar. Idealmente, uno debería usar un puntero no compartido, como auto_ptr, pero ese auto_ptr también tiene algunas dificultades, lo que shared_ptr evita:

class CCarKeys
{
    public:
        CCarKeys(const string& Name) : _Name(Name) {}
        string _Name;
};

class CChild
{
    public:
        CChild (CCarKeys& CarKeys) 
            : _Name("Child"), _CarKeys(CarKeys) {}
        string _Name;
        CCarKeys &_CarKeys;
        void TestHasKeys() {cout << "I got " << _CarKeys._Name << endl;}
    private:
        CChild(CChild const&); // non-copyable
        CChild & operator=(CChild const&); // non-assignable
};

class CDad
{
    public:
        CDad() : 
            _Name("Dad"), 
            _HondaCarKeys("Honda keys"), 
            _ChevyCarKeys("Chevy keys") {}
        string _Name;

        CCarKeys _HondaCarKeys;
        CCarKeys _ChevyCarKeys;

        // also use shared_ptr for the kids. try to avoid raw pointers. 
        boost::shared_ptr<CChild> _Boy;
        boost::shared_otr<CChild> _Girl;

        void MakeBoy() {_Boy.reset(new CChild(_HondaCarKeys));}
        void MakeGirl() {_Girl.reset(new CChild(_ChevyCarKeys));}
private:
    CDad(CDad const&); // non-copyable
    CDad & operator=(CDad const&); // non-assignable
};

Si tuviera que implementar tal jerarquía de clases, iría con esa solución, o simplemente dejaría caer las claves como miembros y las pasaría / crearía cuando fuera necesario para los niños. Algunas otras notas sobre su código:

  • Mejor suelte el " _ " de los miembros o ponerlos al final o usar alguna otra notación. Las implementaciones de C ++ (compilador, C ++ std lib ...) reservan un nombre que comienza con un guión bajo y seguido de una letra mayúscula.
  • Personalmente, me resulta confuso que los nombres de los miembros y las variables comiencen con una letra mayúscula. Lo he visto muy raramente. Pero esto no es mucho para preocuparse, solo se trata de un estilo personal.
  • Hay una regla famosa ( Zero-One-Infinity ) que indica cuándo tienes dos cosas de algo, generalmente deberías poder tener muchas cosas arbitrarias de eso. Entonces, si puedes tener dos hijos, ¿por qué no tener muchos de ellos? Dos parece una elección arbitraria. Pero puede tener una buena razón en su caso, así que ignórelo cuando en su caso tenga sentido.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top