Making something 'public' creates a contract that will be binding upon all inherited classes. Making something 'protected' creates a contract with directly-inherited classes, but does not compel the classes to make such a contract available to any of their descendants.
If one expects that the source code for a base class will be available to anyone who is inheriting from it, and expects that the base class will never change (typically this means that the reason for using the base class is to allow public members and properties of the base-class to be used interchangeably with derived classes, rather than to reduce the amount of code needed for the derived classes) and if all public methods are virtual or tie directly into virtual methods, there's not much disadvantage to using protected fields rather than protected virtual getters/setters. If a descendant class needs to change the way the fields are used, it can simply override all the methods that use them.
If one expects that derived classes may be created in situations where the classes above them in the hierarchy are not completely known or are not immutable, then it may be more appropriate to have protected getters/setters, but that responsibility could be left with whoever creates the 'opaque' layers in the hierarchy.
Example: a collection might maintain a field called 'count'. A base version of the collection may store things in a way that makes it easy to maintain a field that always holds the number of items, but a derived version might store things in a way that makes it difficult. By having a field called "count", the base class promises its direct descendants that it will maintain the number of items in that field. A derived class might store things differently, such that a "count" field wasn't meaningful. Such a class could shadow the count field with a read-only property; its descendants would know that they had to read a property, while descendants of the original class would know that they could read a field.
The most important point is that protected things in a class only create a contract with direct descendants, and those descendants can decide whether or not to make a similar contract available to sub-descendants.
Addendum: the only thing gained by adding protected virtual getters and setters will be the ability for derived classes to change how the base class code accesses the fields/properties. Sometimes this will be necessary, but more often it will create problems. For example, if a collection may frequently have recently-added items deleted, a derived class may wrap things so that the last few items added are kept in a small "bonus" collection and transferred to the main collection after enough additional items are added. Code for the main collection will be expecting its own "count" field to indicate how many items are in the main collection. If a descendant class overrides the "count" property to include its own items, the main code will break. The descendant class should instead shadow the count field so its descendants will see a count that includes the bonus items, but the base class will still see the count which only includes its own items.