Tanto quanto eu posso ver, você tem alguns problemas conflitantes aqui, o que pode ser esclarecido se você pudesse nos dizer com que propósito você está fazendo isso? O código será usado por você / sua equipe ou você está projetando uma API para consumo por outras pessoas?
Se você está apenas tentando projetar uma boa interface para sua funcionalidade, coloque-se no lugar dos clientes de suas funções - escreva alguns testes de unidade. Se ao escrever os testes de unidade, qualquer coisa parecer estranha ou não óbvia, seu design precisa ser melhorado.
Se sua classe é destinada à subclasse, você não deseja membros de dados públicos ou membros de dados protegidos. Os membros de dados que são privados podem ser alterados a qualquer momento sem quebrar as subclasses, enquanto as alterações nos membros protegidos (potencialmente) interrompem as subclasses e as alterações nos membros de dados públicos (muito provavelmente) quebram o código do cliente. Pode parecer tedioso ter um par getter / setter de métodos para manipular um membro de dados, mas vale a pena se você quiser manter a implementação flexível e não se projetar em um canto.
Os métodos virtuais indicam que você está considerando entregar ao cliente da sua classe uma interface que seria virtual pura. Se este for o caso, então você não pode ter membros de dados em uma classe abstrata (virtual pura), o que leva você a métodos virtuais com chamadas de método virtual para obter / definir itens de dados.