1. Diz-se que C++ é uma linguagem orientada a objetos. Você pode [expandir] apresentar as três características da orientação a objetos?
Encapsulamento: O encapsulamento é uma ideia de gerenciamento centralizado que combina dados internos e métodos de implementação sem expor os dados internos e os métodos de implementação ao mundo externo. Ele fornece apenas algumas interfaces para o mundo externo para concluir chamadas de função e operações de dados. A segurança e a consistência de dados são garantidos.
Herança: Herança significa que uma classe pode herdar os métodos e dados de outra classe, o que pode melhorar a reutilização do código e estabelecer o relacionamento entre as classes.
Polimorfismo: Polimorfismo significa que o mesmo método possui comportamentos diferentes para objetos diferentes, o que melhora a flexibilidade do código.
2. Você já entendeu a implementação subjacente do polimorfismo?
A camada inferior do polimorfismo é implementada através de um ponteiro de função virtual. O ponteiro de função virtual aponta para uma tabela de funções virtuais. O endereço de cada função é armazenado na tabela de funções virtuais. A tabela de funções virtuais é uma matriz de ponteiros, e o virtual tabela de funções armazena ponteiros de função., quando uma expressão satisfaz o polimorfismo, ela determina o tipo não na fase de compilação, mas na fase de execução para determinar que tipo é, e então chama a tabela de funções virtuais de acordo com diferentes objetos.
3. Como a função virtual é implementada no nível inferior?
Quando uma função em uma classe é
virtual
modificada, um ponteiro de função virtual aparecerá e o ponteiro de função virtual aponta para a tabela de funções virtuais.
4. (Cenário 1) Existem duas classes cujas variáveis de instância e métodos de função que elas suportam são exatamente iguais. Uma classe implementa uma função virtual. Qual é a diferença entre elas? Eles ocupam a mesma quantidade de memória ao gerar um objeto de instância?
A memória ocupada é diferente. Se a função virtual for implementada, haverá mais um ponteiro de função virtual, que ocupará 4/8 bytes de espaço, e a memória ocupada será diferente.
5. (Cenário 2) Existem quatro classes B e C herdando de A, e D herdando de B e C (herança múltipla).Há uma função pública em A, e então cada um de B e C a reescreveu, e então quer chamá-lo de D. Como chamar a implementação de B ou C?
Use diretamente o operador de domínio de classe
::
para especificar a chamada de domínio de classe.
6. Ainda é o cenário acima. Existe uma variável pública em A. B e C herdam de A, e D herda de B e C. Depois, existem várias variáveis públicas armazenadas em D (tem me orientado, um, Dois porções, três porções)
Esta questão precisa ser discutida em categorias.
Herança ordinária: duas ações (uma ação para B e C).
Herança virtual: uma via, colocada diretamente na área pública.
7. Qual é a diferença entre malloc e novo?
1. O tipo de retorno de malloc é (void*) e requer conversão manual.
2. malloc retorna um erro de alocação de memória
NULL
, enquanto new lança uma exceção.3. Quando new aloca memória, ele chamará o construtor para inicialização e malloc precisará ser inicializado manualmente.
4. Quando malloc aloca memória, você precisa calcular manualmente quanto espaço abrir, mas new não.
5. Novo usa delete para liberar memória e malloc usa free.
6. A camada inferior de new também é chamada
operator new
eoperator new
malloc também é chamada para realizar a alocação de memória.
8. Além de alocar memória, new possui outras operações adicionais além de malloc?
O construtor será chamado para inicialização.
9. New na verdade faz duas coisas, uma é alocar memória e a outra é chamar o construtor da instância. Você já entendeu que new só pode realizar uma operação? Por exemplo, alocar apenas memória sem chamar o construtor ou apenas chamar o construtor sem alocar memória?
Nenhuma memória é alocada, apenas o construtor é chamado: position new(
placement new
) tambémoperator new
.O construtor não é chamado, apenas a memória é alocada:
new (std::nothrow) type
.
10. Calcule o tamanho das duas estruturas a seguir.
struct {
char A;
char B;
int C;
}
struct {
char A;
int C;
char B;
}
Problemas de alinhamento de memória.
O primeiro tem 8 bytes.
O segundo tem 12 bytes.
11. Vejo que você escreveu que conhece STL. Você aprendeu sobre ponteiros inteligentes?
1. O primeiro ponteiro inteligente foi
auto_ptr
, mas esse ponteiro inteligente não realizou totalmente as funções do ponteiro. Ele percebeu principalmenteRAII
a ideia de transferência de permissão.2. Então pareceu
unique_ptr
que a abordagem deste ponteiro inteligente era bastante grosseira, não permitindo a cópia e proibindo a chamada de construtores de cópia.3. Então
shared_ptr
, este ponteiro inteligente resolve o problema original: um endereço só pode ser apontado por um ponteiro inteligente, caso contrário o mesmo bloco de memória será liberado duas vezes. Solução: Use contagem de referência. Mas ainda há o problema das referências circulares.4.
weak_ptr
, um ponteiro inteligente auxiliar, utilizado para resolver o problema de referência circular, permitindo que a variável do ponteiro internoweak_ptr
seja utilizada para representá-lo,weak_ptr
sem modificar a contagem de referência, para que possa resolver muito bem o problema de referência circular.
12. Dê um exemplo de ponteiro inteligente em um cenário prático? Por que usá-lo? Como usá-lo? Tudo bem se eu não usar?
Quando se trata de segurança de exceções, é melhor usar ponteiros inteligentes.
Por exemplo, o seguinte código:
#include<iostream> using namespace std; int div() { int a, b; cin >> a >> b; if (b == 0) throw invalid_argument("除0错误"); return a / b; } void Func() { // 1、如果p1这里new 抛异常会如何? // 2、如果p2这里new 抛异常会如何? // 3、如果div调用这里又会抛异常会如何? int* p1 = new int; int* p2 = new int; cout << div() << endl; delete p1; delete p2; } int main() { try { Func(); } catch (exception& e) { cout << e.what() << endl; } return 0; }
A não utilização de ponteiros inteligentes levará a problemas como a não liberação de várias memórias ou a falta de abertura de espaço.
Os ponteiros podem ser usados sem ponteiros? Sim, mas requer várias camadas de captura de exceções, o que é muito problemático e a legibilidade do código torna-se muito baixa.
13. Você acabou de mencionar que a camada inferior de shared_ptr é compartilhada usando uma contagem de referência.Você conhece outros métodos de gerenciamento de memória?
O mecanismo automático de reciclagem de memória em JAVA usa um conjunto relativamente complexo de algoritmos para calcular o tempo de reciclagem e não há um entendimento profundo dos detalhes.
14. Você já entendeu o mecanismo de expansão dos contêineres de vetores comumente usados em STL?
O mecanismo de expansão é diferente em plataformas diferentes.
vs: 1,5 vezes.
Linux: 2x.
Expansão consiste em reabrir um espaço, copiar o conteúdo original e depois destruir o espaço original.
15: Posso expandir a capacidade três vezes?
Sim, mas pode resultar em muito desperdício de espaço.
16: Você conhece a capacidade inicial do vetor? Quando ocorrerá a expansão inicial?
A capacidade será expandida quando um elemento for adicionado pela primeira vez, e a primeira expansão geralmente será definida como 8 ou 16.