Pergunta

Eu preciso chamar uma função const de um objeto não-const. Veja o exemplo

struct IProcess {
   virtual bool doSomeWork() const = 0L;
};
class Foo : public IProcess {    
  virtual bool doSomeWork() const {
    ...
  }
};

class Bar
{
public:
   const IProcess& getProcess() const {return ...;}
   IProcess& getProcess() {return ...;}

   void doOtherWork {
    getProcess().doSomeWork();        
  }
};

Chamando

getProcess().doSomeWork();

será sempre resulta em uma chamada para

IProcess& getProcess()

Existe outra maneira de chamar

const IProcess& getProcess() const 

a partir de uma função não membro constante? Eu tenho até agora usado

const_cast<const Bar*>(this)->getProcess().doSomeWork();

que faz o truque, mas parece muito complicado.


Edit:. Eu devo mencionar que o código está sendo reformulado e, eventualmente, apenas uma função permanecerá

const IProcess& getProcess() const 

No entanto, atualmente não há um efeito colateral ea chamada const pode retornar uma instância diferente do iProcess algum do tempo.

Por favor, mantenha no tópico.

Foi útil?

Solução

Evite o elenco:. Atribuir a um const Bar * ou o que quer e usar isso para getProcess() chamada

Há algumas razões pedantes de fazer isso, mas também torna mais óbvio que você está fazendo sem forçar o compilador a fazer algo potencialmente inseguro. Concedido, você nunca pode bater esses casos, mas você poderia muito bem escrever algo que não usa um elenco neste caso.

Outras dicas

const_cast é para fundição afastado constness!

Você está fundição de não-const para const que é seguro, por isso uso static_cast:

   static_cast<const Bar*>(this)->getProcess().doSomeWork();

eu quero dizer techincally falando você pode lançar em constness com const_cast, mas não é um uso pragmático do operador. O propósito de novos moldes de estilo (em comparação com o antigo elenco c-style), é comunicar a intenção do elenco. const_cast é um cheiro de código, e sua utilização deve ser revista pelo menos. static_cast por outro lado, é seguro. Mas é uma questão de estilo C ++.

Ou você pode criar um novo método de const (privado), e chamar isso de doOtherWork:

  void doSomeWorkOnProcess() const { getProcess().doSomeWork(); }

Usando um const temporário é também uma opção (resposta por "MSN"):

   const Bar* _this = this;
   _this->getProcess().doSomeWork();

Se getProcess() e getProcess() const não estão retornando uma referência para o mesmo objeto (mas de forma diferente qualificado), então isso indicaria uma má concepção class Bar. Sobrecarga no constness da função não é uma boa maneira de distinguir funções com comportamentos diferentes.

Se eles estão retornando uma referência ao mesmo objeto, em seguida:

const_cast<const Bar*>(this)->getProcess().doSomeWork();

e

getProcess().doSomeWork();

chamada exatamente a mesma função doSomeWork() por isso não há necessidade de usar o const_cast.

Se o elenco é muito feio para você, você poderia, em vez adicionar um método para Bar que simplesmente retorna uma referência const para *this:

Bar const& as_const() const {
    return *this;    // Compiler adds "const" without needing static_cast<>
}

Você pode então chamar qualquer método const em Bar apenas por prepending as_const()., por exemplo:.

as_const().getProcess().doSomeWork();

Você não tem que fazer nenhum truque fundição se a função não está sobrecarregado. Chamar um método const de um objeto não-const é bom. Está chamando um método não-const de um objeto const que é proibido. Se os métodos são substituídas com uma const e função não-const, em seguida, converter o objeto para const vai fazer o truque:

const_cast<const IProcess&> (getProcess()).doSomeWork();

EDIT: Eu não li toda a questão. Sim, você precisa const_cast o este ponteiro ou fazer o doOtherWork função const a chamada const iProcess & getProcess () const .

o ponto permanece que você não precisa de um objeto const a chamada doSomeWork . Desde que é o objetivo, você precisa o método const denominada?

Outra opção seria a de renomear as funções over-montado. Isso seria realmente uma boa idéia se os dois função realmente tem comportamento diferente / efeitos colaterais. Caso contrário, o efeito da chamada de função não seria óbvio.

definir um modelo

template< class T >
const T & addConst ( T & t ) 
{
    return t;
}

e chamar

addConst( getProcess() ).doSomeWork();

Bem, você pode declarar

void doOtherWork const ()

?

Isso iria fazê-lo.

Eu acho que o método const_cast é sua melhor opção. Esta é apenas uma limitação do quadro const em C ++. Acho que a única maneira que você poderia evitar o vazamento é definir um método que retorna const exemplo iProcess independentemente. Por exemplo.

const IProcess* getProcessConst() const { return ... }
...
getProcessConst().doSomeWork();

Eu suponho que você quer DoOtherWork para chamar um de seus dois chamadas getprocess dependendo sobre se ele é chamado de um objeto const ou não.

O melhor que posso sugerir é o seguinte:

class Bar
{
public:
   const IProcess& getProcess() const {return ...;}
   IProcess& getProcess() {return ...;}

   void doOtherWork {            // should use getProcess()      
    getProcess().doSomeWork();        
  }
   void doOtherWork const {
    getProcess().doSomeWork();   // should use getProcess() const     
  }
};

Mesmo se isso funciona, isso parece um mau cheiro para mim. Eu ficaria muito cuidado com o comportamento da classe mudar radicalmente de acordo com o constness de um objeto.

Postado por Monjardin
Outra opção seria a de renomear as funções over-montado. Isso seria realmente uma boa idéia se os dois função realmente tem comportamento diferente / efeitos colaterais. Caso contrário, o efeito da chamada de função não seria óbvio.

iProcess e é acessado em outro código principalmente através de uma propriedade

__declspec(property(get=getProcess)) IProcess& Process;

então renomear não era uma opção. Maioria das vezes const ness da função de chamada corresponde getProcess () então não havia nenhum problema.

Você está basicamente preso com renomeando o outro método ou const_cast.

BTW, esta é uma das razões que copy-on-write ponteiros inteligentes realmente não funcionam bem em C ++. Um ponteiro inteligente copy-on-write é aquele que pode ser compartilhado infinitamente. Quando um usuário acessa os dados em um contexto não-const, uma cópia dos dados é feita (se o usuário não mantém a única referência). Este tipo de ponteiro pode ser muito conveniente para usar quando compartilhando estruturas de dados grandes que apenas alguns clientes precisam modificar. A implementação mais "lógico" é ter uma const e não-const operator->. A versão const apenas retorna a referência subjacente. A versão não-const faz a verificação da referência original e cópia. Ela não consegue ser útil porque um ponteiro inteligente não-const usará a operadora> por padrão, mesmo se você quiser usar a versão const const não. A exigência const_cast torna muito user-hostil.

Estou acolhendo qualquer um que prova que estou errado e mostra um ponteiro user-friendly copy-on-write em C ++ ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top