Pergunta

C ++ novato pergunta. Por favor, verifique que eu estou fazendo certo.

Eu tenho uma classe de aplicações globais desova São pequenas as crianças e eu preciso dar acesso as crianças para algumas das instalações de aplicativos. Então eu decidi passá-las para as crianças por referência.

Eu testei a idéia, como mostrado abaixo. Parece funcionar bem. Eu só queria ter certeza que eu não estou fazendo algo perigoso. Poderia estar lá qualquer armadilhas I negligenciados?

Dad cria filhos e dá-lhes as chaves do carro:

#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();
}
Foi útil?

Solução

Parece bom para mim (se as chaves é tudo que eles precisam). Eles podem precisar de alguns outros serviços de papai que são solicitados mais tarde - como:

Wallet += MyDad.GasMoney(REQUEST_MAX_AND_PROMISE_TO_BE_HOME_BY_10PM) ;

Mas eles não têm uma referência ao pai, para que eles não serão capazes de fazer isso. Então eu teria o construtor CChild tomar uma referência this também.

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

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

etc.

E então construtor CChild precisa tomar ICashProvider e IChaffeur, como seria CWife e CGirlfriend (e CBoyfriend, talvez). Neste ponto, eu acho que você pode perceber que este nível de granularidade é inútil em face das responsabilidades de Dad e você apenas dar a todos this e tem pedidos Dad autenticar forçando chamadores de enviar sua própria this em alguns métodos, para que você não tem Dad realizando incesto ou mudar a fralda do CWife.

Outras dicas

passagem por referência é o mesmo que passar pelo ponteiro, exceto para a semântica eo fato de que você não pode fazer nada com o próprio ponteiro se passando por referência.

Seu código é OK.

No seu caso particular, as chaves do carro não são susceptíveis de ser concedida de forma permanente, mas sim solicitado quando necessário e concedido na base por solicitação. Por isso é mais

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

No caso mais genral de classe aplicativo principal e as crianças, que tal criar os dados objeto compartilhado por aplicativo e crianças em main (), e passando thereferences a todos.

É possível e em seu código não está causando danos. Mas é perigoso, porque se você copiar CDAD, em seguida, as chaves e ponteiros serão copiados junto. Os objectos que os ponteiros irá apontar para, e a referência dentro desses objectos, no entanto, irá permanecer o mesmo. Se o objeto cdad original, então sai do escopo, as referências nos objetos referenciados pelos ponteiros estão pendurados, fazendo referência a nenhum objeto mais válido.

Talvez você pode vidas reversa: Criar as chaves na pilha, e as crianças como membros normais dentro da classe. Então, se você copiar o pai, as crianças são copiados, mas as chaves não são. Eu acho que as chaves são imutáveis, assim você pode compartilhar a mesma chave entre vários filhos.

Este leva a outro ponto: se as chaves são razoáveis ??pequeno (leia-se: não enorme) e imutável (assim você não tem anomalias de atualização se você mudar uma chave, mas não os outros), considere a criação it não na pilha também - então eles são automaticamente copiados junto também, e passá-las para as crianças quando eles precisam da chave. Você pode torná-los ponteiros normais das crianças, mas eu acho que é feio, porque a criança não faz conter uma chave - mas usa-lo. Assim, um ponteiro / referência ou um parâmetro de função se encaixa bem, mas não um "real" membro de dados.

Se você está indo com a chave compartilhada e as chaves-on-heap, você deve usar ponteiros inteligentes - porque você tem que manter o controle de todas as crianças e pais. Se a última criança / pai sai do escopo, você tem que excluir a chave novamente. Você usa boost::shared_ptr para isso:

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

É claro, você pode evitar toda esta complexidade, apenas fazendo a classe não-copiável CDAD. Então você pode usar a sua solução original, apenas com fazer as crianças usam um shared_ptr e fazer as crianças não-copiável também. Idealmente, deve-se usar um ponteiro não-compartilhado, como auto_ptr, mas que auto_ptr tem algumas armadilhas também, que shared_ptr todas 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
};

Se eu tivesse que implementar uma hierarquia de classes, eu iria com essa solução, ou apenas deixar as chaves como membros, e passar / criá-los quando necessário para as crianças. Algumas outras notas sobre o código:

  • Melhor deixar cair o "_" de membros ou colocá-los no final ou usar alguma outra notação. Um nome que começa com um sublinhado e é seguido por uma letra maiúscula é reservado pelo C ++ implementações (compilador, C ++ std lib ...).
  • Eu, pessoalmente encontrá-lo confuso para ter nomes de membros e variáveis ??começar com uma letra maiúscula. Eu vi que só muito raramente. Mas isso não é muito de se preocupar, é apenas sobre o estilo pessoal.
  • Existe uma regra famosa ( Zero-One-Infinito) que os estados quando você tem duas coisas de alguma coisa, você geralmente deve ser capaz de ter arbitrárias muitas coisas de que. Então, se você pode ter duas crianças - por que não têm muitos deles? Dois parece uma escolha arbitrária. Mas pode ter uma boa razão no seu caso -. Modo ignorar isso quando, no seu caso, faz sentido
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top