In your example, x will be a Base, this is because you are creating a new Base object when you call the function. That is, on the function call, the constructor for Base is called, creating a Base b copied from the argument's (x's) Base subobject (known as object slicing). It's not being treated as a Base, it creates a new Base
If you, however, take the argument as a Base &, it will be treated as a Derived, consider the following code:
#include <iostream>
class Base {
public:
virtual void func() const {
std::cout << "Base::Func()" << std::endl;
}
};
class Derived : public Base {
public:
virtual void func() const {
std::cout << "Derived::Func()" << std::endl;
}
};
int do_func_value(Base b){
b.func(); // will call Base::func
}
int do_func_ref(const Base & b){
b.func(); // will call whatever b's actual type is ::func
}
int main(void){
Derived d;
do_func_value(d);
do_func_ref(d);
return 0;
}
this outputs:
Base::Func()
Derived::Func()