Chamar uma função const de um objeto não-const
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.
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 const
ness 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 ++ ...