Q:

static and dynamic resolution in C++

The text I'm following says:    

A call to a virtual function using an object is always resolved statically. You only get a dynamic resolution through a pointer or a reference.

Now consider the following program:    
#include <iostream>

class Mainclass{
    protected: 
        double length{1.0};
        double width{1.0};
        double height{1.0};

    public:
        Mainclass(double lv, double wv, double hv):length{lv}, width{wv}, height{hv}{
            std::cout<<"Three args box ran"<<std::endl;
        }

        void showVolume() const{
            std::cout<<"Mainclass usable volume is: "<<Volume()<<std::endl;
        }

        virtual double Volume() const{
            return length*width*height;
        }

};

class Derivedclass: public Mainclass{
    public: 
        Derivedclass(double lv, double wv, double hv): Mainclass{lv, wv, hv}{}

        double Volume() const{
            return 0.85*length*width*height;
        }

};

int main(){
    Mainclass first{20.0, 30.0, 40.0};
    Derivedclass second {20.0, 30.0, 40.0};

    first.showVolume();
    second.showVolume();
}   

Output:  
Three args box ran
Three args box ran
Mainclass usable volume is: 24000
Mainclass usable volume is: 20400

Here, I'm calling the base class and the derived class objects via their object instances and not through a pointer. But it appears that the function is being resolved dynamically. Was the text wrong? If not what did it mean?

A:

"A call to a virtual function using an object is always resolved statically. You only get a dynamic resolution through a pointer or a reference."

This sentence isn't so much describing a rule of the C++ language as a shortcut compilers are allowed to take.
You are calling showFunction directly on the names of objects.  So suppose showFunction were declared virtual.  The compiler knows the exact types of the objects called first and second: there's no way they could actually be objects of some other type.  So although the language says any overriding function must be called by first.showVolume() and second.showVolume(), there's no possible way the result will be any functions other than the ones the compiler can find immediately, so it doesn't actually need to put any code for determining which function to call in the resulting program.  The correct function Mainclass::showVolume() (or Derivedclass::showVolume(), if it existed), can be called directly, which can be slightly more efficient.
The quote doesn't apply to the call of Volume() inside showVolume().  Since Volume names a non-static member, Volume() means the same as this->Volume().  this is a pointer, which might or might not point at an object whose complete type matches the type Mainclass* const of the pointer.  So in this case, the compiler is required to do dynamic resolution to determine which function to call.
But one more thing to note: it's true you can only get dynamic resolution through a pointer or reference, but it's not true you always get dynamic resolution through a pointer or reference.  When a function is named as a "qualified id" using the :: token, the language says the function called is determined statically, and overrides are ignored.  For example, if your code in showVolume() changed to use either Mainclass::Volume() or this->Mainclass::Volume(), you would see that it never calls Derivedclass::Volume.

