Programming with abstract data types means that when you write:
struct A { int i; float k; };
You can use A a; as abstraction of some bits like [00000000][00000000]. (with proper number of bits)
Inheritance adds the following feature:
class A { public: virtual void f()=0; };
class B1 : public A { public: void f() { ... } int a; int b; };
class B2 : public A { public: void f() { ... } int i; float k; };
void algo(A &a) { a.f(); a.f(); }
int main() { B1 b; algo(b); B2 b2; algo(b2); }
I.e. when there are several classes like B1,B2,B3 the algorithms like g() can work with all of them, even if the format of the bits is changing between B1 and B2, i.e. the { int a; int b; } is different from { int i; float k; }.