Do ponto de vista do design, por que, em C ++, não existe uma classe-base mãe de todas, o que normalmente ocorre object
em outras linguagens?
c++
language-design
Slezica
fonte
fonte
typedef
s únicos. Com uma hierarquia de classes mais genérica, você pode apenas usarobject
ouiterator
.Respostas:
A decisão definitiva pode ser encontrada nas Perguntas frequentes da Stroustrup . Em suma, não transmite nenhum significado semântico. Terá um custo. Os modelos são mais úteis para contêineres.
fonte
Objects must be heap-allocated to be polymorphic
- Eu não acho que esta afirmação é geralmente correta. Você pode definitivamente criar uma instância de uma classe polimórfica na pilha e passá-la como um ponteiro para uma de suas classes base, produzindo um comportamento polimórfico.Foo
a uma referência aBar
quandoBar
não herdaFoo
, deterministicamente , lança uma exceção. Em C ++, a tentativa de lançar um ponteiro para Foo em um ponteiro para Barra poderia enviar um robô de volta no tempo para matar Sarah Connor.Vamos primeiro pensar sobre por que você gostaria de ter uma classe base em primeiro lugar. Posso pensar em alguns motivos diferentes:
Estas são as duas boas razões pelas quais as linguagens da marca Smalltalk, Ruby e Objective-C têm classes base (tecnicamente, Objective-C não tem realmente uma classe base, mas para todos os efeitos e propósitos, ela tem).
Para o nº 1, a necessidade de uma classe base que unifique todos os objetos em uma única interface é evitada pela inclusão de modelos em C ++. Por exemplo:
void somethingGeneric(Base); Derived object; somethingGeneric(object);
é desnecessário, quando você pode manter a integridade do tipo por meio de polimorfismo paramétrico!
template <class T> void somethingGeneric(T); Derived object; somethingGeneric(object);
Para o nº 2, enquanto em Objective-C, os procedimentos de gerenciamento de memória são parte da implementação de uma classe e são herdados da classe base, o gerenciamento de memória em C ++ é executado usando composição em vez de herança. Por exemplo, você pode definir um wrapper de ponteiro inteligente que fará a contagem de referência em objetos de qualquer tipo:
template <class T> struct refcounted { refcounted(T* object) : _object(object), _count(0) {} T* operator->() { return _object; } operator T*() { return _object; } void retain() { ++_count; } void release() { if (--_count == 0) { delete _object; } } private: T* _object; int _count; };
Então, em vez de chamar métodos no próprio objeto, você chamaria métodos em seu invólucro. Isso não apenas permite uma programação mais genérica: também permite separar interesses (uma vez que, idealmente, seu objeto deveria estar mais preocupado com o que deveria fazer, do que como sua memória deveria ser gerenciada em diferentes situações).
Por último, em uma linguagem que possui objetos primitivos e reais como C ++, os benefícios de ter uma classe base (uma interface consistente para todos os valores) são perdidos, já que você tem certos valores que não podem estar em conformidade com essa interface. Para usar primitivos nesse tipo de situação, você precisa transformá-los em objetos (se o seu compilador não fizer isso automaticamente). Isso cria muitas complicações.
Então, uma resposta curta para sua pergunta: C ++ não tem uma classe base porque, tendo polimorfismo paramétrico por meio de templates, não precisa.
fonte
object
(System.Object
), mas não precisam ser. Para o compilador,int
eSystem.Int32
são apelidos e podem ser usados alternadamente; o tempo de execução lida com boxe quando necessário.std::shared_ptr
que deve ser usado.O paradigma dominante para variáveis C ++ é a passagem por valor, não a passagem por ref. Forçar tudo a ser derivado de uma raiz
Object
tornaria a passagem deles por valor um erro ipse facto.(Porque aceitar um objeto por valor como parâmetro, por definição iria cortá-lo e remover sua alma).
Isso não é bem-vindo. C ++ faz você pensar se você deseja valor ou semântica de referência, dando-lhe a escolha. Isso é importante na computação de desempenho.
fonte
Object
seria relativamente pequeno.O problema é que EXISTE esse tipo em C ++! É sim
void
. :-) Qualquer ponteiro pode ser lançado implicitamente com segurançavoid *
, incluindo ponteiros para tipos básicos, classes sem tabela virtual e classes com tabela virtual.Uma vez que deve ser compatível com todas essas categorias de objetos,
void
ele mesmo não pode conter métodos virtuais. Sem funções virtuais e RTTI, nenhuma informação útil sobre o tipo pode ser obtidavoid
(ele corresponde a TODOS os tipos, então pode dizer apenas coisas que são verdadeiras para TODOS os tipos), mas as funções virtuais e RTTI tornariam os tipos simples muito ineficazes e impediriam o C ++ de ser uma linguagem adequada para programação de baixo nível com acesso direto à memória, etc.Então, existe esse tipo. Ele apenas fornece uma interface muito minimalista (na verdade, vazia) devido à natureza de baixo nível da linguagem. :-)
fonte
void
.void
ela não será compilada e você obterá este erro . Em Java, você poderia ter uma variável do tipoObject
e ela funcionaria. Essa é a diferença entrevoid
um tipo "real". Talvez seja verdade quevoid
é o tipo base para tudo, mas como não fornece nenhum construtor, método ou campo, não há como saber se ele está lá ou não. Esta afirmação não pode ser provada ou refutada.void
é um tipo (e descobri um uso? :
um tanto inteligente de ), mas ainda está muito longe de ser uma classe base universal. Por um lado, é "um tipo incompleto que não pode ser completado" e, por outro, não existe nenhumvoid&
tipo.C ++ é uma linguagem fortemente tipada. No entanto, é intrigante que ele não tenha um tipo de objeto universal no contexto da especialização de modelo.
Pegue, por exemplo, o padrão
template <class T> class Hook; template <class ReturnType, class ... ArgTypes> class Hook<ReturnType (ArgTypes...)> { ... ReturnType operator () (ArgTypes... args) { ... } };
que pode ser instanciado como
Hook<decltype(some_function)> ...;
Agora, vamos supor que queremos o mesmo para uma função específica. Gostar
template <auto fallback> class Hook; template <auto fallback, class ReturnType, class ... ArgTypes> class Hook<ReturnType fallback(ArgTypes...)> { ... ReturnType operator () (ArgTypes... args) { ... } };
com a instanciação especializada
Mas, infelizmente, embora a classe T possa representar qualquer tipo (classe ou não) antes da especialização, não há equivalente
auto fallback
(estou usando essa sintaxe como o não-tipo genérico mais óbvio neste contexto) que poderia substituir qualquer argumento de modelo sem tipo antes da especialização.Portanto, em geral, esse padrão não é transferido de argumentos de template de tipo para argumentos de template não-tipo.
Como acontece com muitos cantos na linguagem C ++, a resposta provavelmente é "nenhum membro do comitê pensou nisso".
fonte
ReturnType fallback(ArgTypes...)
funcionasse, seria um projeto ruim.template <class T, auto fallback> class Hook; template <class ReturnType, class ... ArgTypes> class Hook<ReturnType (ArgTypes...), ReturnType(*fallback)(ArgTypes...)> ...
faz o que você quer e significa que os parâmetros do modeloHook
são de tiposC ++ foi inicialmente chamado de "C com classes". É uma progressão da linguagem C, ao contrário de outras coisas mais modernas como C #. E você não pode ver C ++ como uma linguagem, mas como uma base de linguagens (Sim, estou me lembrando do livro de Scott Meyers Effective C ++).
O próprio C é uma mistura de linguagens, a linguagem de programação C e seu pré-processador.
C ++ adiciona outra combinação:
a abordagem de classe / objetos
modelos
o STL
Eu pessoalmente não gosto de algumas coisas que vêm diretamente de C para C ++. Um exemplo é o recurso enum. A maneira como o C # permite que o desenvolvedor o use é muito melhor: ele limita o enum em seu próprio escopo, tem uma propriedade Count e é facilmente iterável.
Como C ++ queria ser retrocompatível com C, o designer foi muito permissivo em permitir que a linguagem C entrasse em sua totalidade para C ++ (existem algumas diferenças sutis, mas não me lembro de nada que você pudesse fazer usando um compilador C que você não poderia fazer usando um compilador C ++).
fonte