 
  
   
  
   
  
   
  
  #include <iostream>
class Animal {
    public: virtual void sound() {//  перегрузка раз
        std::cout << "Animal.sound()" << '\n';
    }
    public: virtual void sound(int i) {// перегрузка два
        std::cout << "Animal.sound(int)" << '\n';
    }
};
class Cat : public Animal{
    
    public: void sound () override {// overriding (а не redefinition) будет успешным: имя, параметры, возвращаемый тип есть в базовом классе, всё ок
        std::cout << "Cat.sound()" << '\n';
    }
};
int main() {
    Cat * cat1 = new Cat();
    cat1 -> sound(); // Cat.sound()
    //! cat1 -> sound(1); // no matching function for call to 'Cat::sound(int)'  
/* 
В книге Bruce Eckel  Thinking in C++, 2nd Edition это показано в NameHiding2.cpp и называется hiding, сокрытие. То есть если я хочу вызывать виртуальные методы у типов Cat, Cat * или Cat & - то мне нужно определить новую версию для каждой перегрузки. 
*/
    delete cat1;
} 
  
   
  
  Судя по вопросу для вас это одно и то же.
Повышение char до int не зависимо от того какой конкретно char в данной системе вполне стандартизовано и укладывается в стандартное расширение целочисленных типов.
 
  
   
  
  попробуй virtual.
 
  
  class Base{
public:
    void method(){}
    void method(int i){}
};
class Derived : public Base {
public:
    void method(char c){}
};
int main(void) {
    Derived d;
    d.method(1);// хотел наглядно показать экранирование метода при redefinition (а не overriding) и удивился, что не возникает предупреждения несмотря на флаг.  Дальше полез гуглить - и понял, что не понимаю.
    return 0;
}