diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 597b0fb..0338387 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,106 @@
 2017-06-02  Simon Marchi  <simon.marchi@polymtl.ca>
 
+	* breakpoint.h (struct breakpoint_ops) <dtor>: Remove.
+	(struct breakpoint) <~breakpoint>: New.
+	(struct watchpoint): Inherit from breakpoint.
+	<~watchpoint>: New.
+	<base>: Remove.
+	(struct tracepoint): Inherit from breakpoint.
+	<base>: Remove.
+	* breakpoint.c (longjmp_breakpoint_ops): Remove.
+	(struct longjmp_breakpoint): Inherit from breakpoint.
+	<~longjmp_breakpoint>: New.
+	<base>: Remove.
+	(new_breakpoint_from_type): Remove casts.
+	(watchpoint_in_thread_scope): Remove reference to base field.
+	(watchpoint_del_at_next_stop): Likewise.
+	(update_watchpoint): Likewise.
+	(watchpoint_check): Likewise.
+	(bpstat_check_watchpoint): Likewise.
+	(set_longjmp_breakpoint): Likewise.
+	(struct fork_catchpoint): Inherit from breakpoint.
+	<base>: Remove.
+	(struct solib_catchpoint): Inherit from breakpoint.
+	<~solib_catchpoint>: New.
+	<base>: Remove.
+	(dtor_catch_solib): Change to ...
+	(solib_catchpoint::~solib_catchpoint): ... this.
+	(breakpoint_hit_catch_solib): Remove reference to base field.
+	(add_solib_catchpoint): Likewise.
+	(create_fork_vfork_event_catchpoint): Likewise.
+	(struct exec_catchpoint): Inherit from breakpoint.
+	<~exec_catchpoint>: New.
+	<base>: Remove.
+	(dtor_catch_exec): Change to ...
+	(exec_catchpoint::~exec_catchpoint): ... this.
+	(dtor_watchpoint): Change to ...
+	(watchpoint::~watchpoint): ... this.
+	(watch_command_1): Remove reference to base field.
+	(catch_exec_command_1): Likewise.
+	(base_breakpoint_dtor): Change to ...
+	(breakpoint::~breakpoint): ... this.
+	(base_breakpoint_ops): Remove dtor field value.
+	(longjmp_bkpt_dtor): Change to ...
+	(longjmp_breakpoint::~longjmp_breakpoint): ... this.
+	(strace_marker_create_breakpoints_sal): Remove reference to base
+	field.
+	(delete_breakpoint): Don't manually call breakpoint destructor.
+	(create_tracepoint_from_upload): Remove reference to base field.
+	(trace_pass_set_count): Likewise.
+	(initialize_breakpoint_ops): Don't initialize
+	momentary_breakpoint_ops, don't set dtors.
+	* ada-lang.c (struct ada_catchpoint): Inherit from breakpoint.
+	<~ada_catchpoint>: New.
+	<base>: Remove.
+	(create_excep_cond_exprs): Remove reference to base field.
+	(dtor_exception): Change to ...
+	(ada_catchpoint::~ada_catchpoint): ... this.
+	(dtor_catch_exception): Remove.
+	(dtor_catch_exception_unhandled): Remove.
+	(dtor_catch_assert): Remove.
+	(create_ada_exception_catchpoint): Remove reference to base
+	field.
+	(initialize_ada_catchpoint_ops): Don't set dtors.
+	* break-catch-sig.c (struct signal_catchpoint): Inherit from
+	breakpoint.
+	<~signal_catchpoint>: New.
+	<base>: Remove.
+	(signal_catchpoint_dtor): Change to ...
+	(signal_catchpoint::~signal_catchpoint): ... this.
+	(create_signal_catchpoint): Remove reference to base field.
+	(initialize_signal_catchpoint_ops): Don't set dtor.
+	* break-catch-syscall.c (struct syscall_catchpoint): Inherit
+	from breakpoint.
+	<~syscall_catchpoint>: New.
+	<base>: Remove.
+	(dtor_catch_syscall): Change to ...
+	(syscall_catchpoint::~syscall_catchpoint): ... this.
+	(create_syscall_event_catchpoint): Remove reference to base
+	field.
+	(initialize_syscall_catchpoint_ops): Don't set dtor.
+	* break-catch-throw.c (struct exception_catchpoint): Inherit
+	from breakpoint.
+	<~exception_catchpoint>: New.
+	<base>: Remove.
+	(dtor_exception_catchpoint): Change to ...
+	(exception_catchpoint::~exception_catchpoint): ... this.
+	(handle_gnu_v3_exceptions): Remove reference to base field.
+	(initialize_throw_catchpoint_ops): Don't set dtor.
+	* ctf.c (ctf_get_traceframe_address): Remove reference to base
+	field.
+	* remote.c (remote_get_tracepoint_status): Likewise.
+	* tracefile-tfile.c (tfile_get_traceframe_address): Likewise.
+	* tracefile.c (tracefile_fetch_registers): Likewise.
+	* tracepoint.c (actions_command): Likewise.
+	(validate_actionline): Likewise.
+	(tfind_1): Likewise.
+	(get_traceframe_location): Likewise.
+	(find_matching_tracepoint_location): Likewise.
+	(parse_tracepoint_status): Likewise.
+	* mi/mi-cmd-break.c (mi_cmd_break_passcount): Likewise.
+
+2017-06-02  Simon Marchi  <simon.marchi@polymtl.ca>
+
 	* breakpoint.c (struct longjmp_breakpoint): New struct.
 	(is_tracepoint_type): Change return type to bool.
 	(is_longjmp_type): New function.
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 25c49c5..f90907a 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12257,14 +12257,11 @@ static const struct bp_location_ops ada_catchpoint_location_ops =
   ada_catchpoint_location_dtor
 };
 
-/* An instance of this type is used to represent an Ada catchpoint.
-   It includes a "struct breakpoint" as a kind of base class; users
-   downcast to "struct breakpoint *" when needed.  */
+/* An instance of this type is used to represent an Ada catchpoint.  */
 
-struct ada_catchpoint
+struct ada_catchpoint : public breakpoint
 {
-  /* The base class.  */
-  struct breakpoint base;
+  ~ada_catchpoint () override;
 
   /* The name of the specific exception the user specified.  */
   char *excep_string;
@@ -12285,7 +12282,7 @@ create_excep_cond_exprs (struct ada_catchpoint *c)
     return;
 
   /* Same if there are no locations... */
-  if (c->base.loc == NULL)
+  if (c->loc == NULL)
     return;
 
   /* Compute the condition expression in text form, from the specific
@@ -12295,7 +12292,7 @@ create_excep_cond_exprs (struct ada_catchpoint *c)
 
   /* Iterate over all the catchpoint's locations, and parse an
      expression for each.  */
-  for (bl = c->base.loc; bl != NULL; bl = bl->next)
+  for (bl = c->loc; bl != NULL; bl = bl->next)
     {
       struct ada_catchpoint_location *ada_loc
 	= (struct ada_catchpoint_location *) bl;
@@ -12316,7 +12313,7 @@ create_excep_cond_exprs (struct ada_catchpoint *c)
 	    {
 	      warning (_("failed to reevaluate internal exception condition "
 			 "for catchpoint %d: %s"),
-		       c->base.number, e.message);
+		       c->number, e.message);
 	    }
 	  END_CATCH
 	}
@@ -12327,17 +12324,11 @@ create_excep_cond_exprs (struct ada_catchpoint *c)
   do_cleanups (old_chain);
 }
 
-/* Implement the DTOR method in the breakpoint_ops structure for all
-   exception catchpoint kinds.  */
+/* ada_catchpoint destructor.  */
 
-static void
-dtor_exception (enum ada_exception_catchpoint_kind ex, struct breakpoint *b)
+ada_catchpoint::~ada_catchpoint ()
 {
-  struct ada_catchpoint *c = (struct ada_catchpoint *) b;
-
-  xfree (c->excep_string);
-
-  bkpt_breakpoint_ops.dtor (b);
+  xfree (this->excep_string);
 }
 
 /* Implement the ALLOCATE_LOCATION method in the breakpoint_ops
@@ -12623,12 +12614,6 @@ print_recreate_exception (enum ada_exception_catchpoint_kind ex,
 
 /* Virtual table for "catch exception" breakpoints.  */
 
-static void
-dtor_catch_exception (struct breakpoint *b)
-{
-  dtor_exception (ada_catch_exception, b);
-}
-
 static struct bp_location *
 allocate_location_catch_exception (struct breakpoint *self)
 {
@@ -12675,12 +12660,6 @@ static struct breakpoint_ops catch_exception_breakpoint_ops;
 
 /* Virtual table for "catch exception unhandled" breakpoints.  */
 
-static void
-dtor_catch_exception_unhandled (struct breakpoint *b)
-{
-  dtor_exception (ada_catch_exception_unhandled, b);
-}
-
 static struct bp_location *
 allocate_location_catch_exception_unhandled (struct breakpoint *self)
 {
@@ -12729,12 +12708,6 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops;
 
 /* Virtual table for "catch assert" breakpoints.  */
 
-static void
-dtor_catch_assert (struct breakpoint *b)
-{
-  dtor_exception (ada_catch_assert, b);
-}
-
 static struct bp_location *
 allocate_location_catch_assert (struct breakpoint *self)
 {
@@ -13060,13 +13033,13 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch,
     = ada_exception_sal (ex_kind, excep_string, &addr_string, &ops);
 
   c = new ada_catchpoint ();
-  init_ada_exception_breakpoint (&c->base, gdbarch, sal, addr_string,
+  init_ada_exception_breakpoint (c, gdbarch, sal, addr_string,
 				 ops, tempflag, disabled, from_tty);
   c->excep_string = excep_string;
   create_excep_cond_exprs (c);
   if (cond_string != NULL)
-    set_breakpoint_condition (&c->base, cond_string, from_tty);
-  install_breakpoint (0, &c->base, 1);
+    set_breakpoint_condition (c, cond_string, from_tty);
+  install_breakpoint (0, c, 1);
 }
 
 /* Implement the "catch exception" command.  */
@@ -14090,7 +14063,6 @@ initialize_ada_catchpoint_ops (void)
 
   ops = &catch_exception_breakpoint_ops;
   *ops = bkpt_breakpoint_ops;
-  ops->dtor = dtor_catch_exception;
   ops->allocate_location = allocate_location_catch_exception;
   ops->re_set = re_set_catch_exception;
   ops->check_status = check_status_catch_exception;
@@ -14101,7 +14073,6 @@ initialize_ada_catchpoint_ops (void)
 
   ops = &catch_exception_unhandled_breakpoint_ops;
   *ops = bkpt_breakpoint_ops;
-  ops->dtor = dtor_catch_exception_unhandled;
   ops->allocate_location = allocate_location_catch_exception_unhandled;
   ops->re_set = re_set_catch_exception_unhandled;
   ops->check_status = check_status_catch_exception_unhandled;
@@ -14112,7 +14083,6 @@ initialize_ada_catchpoint_ops (void)
 
   ops = &catch_assert_breakpoint_ops;
   *ops = bkpt_breakpoint_ops;
-  ops->dtor = dtor_catch_assert;
   ops->allocate_location = allocate_location_catch_assert;
   ops->re_set = re_set_catch_assert;
   ops->check_status = check_status_catch_assert;
diff --git a/gdb/break-catch-sig.c b/gdb/break-catch-sig.c
index 5f02fe6..3eede93 100644
--- a/gdb/break-catch-sig.c
+++ b/gdb/break-catch-sig.c
@@ -38,16 +38,12 @@ typedef enum gdb_signal gdb_signal_type;
 DEF_VEC_I (gdb_signal_type);
 
 /* An instance of this type is used to represent a signal catchpoint.
-   It includes a "struct breakpoint" as a kind of base class; users
-   downcast to "struct breakpoint *" when needed.  A breakpoint is
-   really of this type iff its ops pointer points to
+   A breakpoint is really of this type iff its ops pointer points to
    SIGNAL_CATCHPOINT_OPS.  */
 
-struct signal_catchpoint
+struct signal_catchpoint : public breakpoint
 {
-  /* The base class.  */
-
-  struct breakpoint base;
+  ~signal_catchpoint () override;
 
   /* Signal numbers used for the 'catch signal' feature.  If no signal
      has been specified for filtering, its value is NULL.  Otherwise,
@@ -89,17 +85,11 @@ signal_to_name_or_int (enum gdb_signal sig)
 
 
 
-/* Implement the "dtor" breakpoint_ops method for signal
-   catchpoints.  */
+/* signal_catchpoint destructor.  */
 
-static void
-signal_catchpoint_dtor (struct breakpoint *b)
+signal_catchpoint::~signal_catchpoint ()
 {
-  struct signal_catchpoint *c = (struct signal_catchpoint *) b;
-
-  VEC_free (gdb_signal_type, c->signals_to_be_caught);
-
-  base_breakpoint_ops.dtor (b);
+  VEC_free (gdb_signal_type, this->signals_to_be_caught);
 }
 
 /* Implement the "insert_location" breakpoint_ops method for signal
@@ -372,11 +362,11 @@ create_signal_catchpoint (int tempflag, VEC (gdb_signal_type) *filter,
   struct gdbarch *gdbarch = get_current_arch ();
 
   c = new signal_catchpoint ();
-  init_catchpoint (&c->base, gdbarch, tempflag, NULL, &signal_catchpoint_ops);
+  init_catchpoint (c, gdbarch, tempflag, NULL, &signal_catchpoint_ops);
   c->signals_to_be_caught = filter;
   c->catch_all = catch_all;
 
-  install_breakpoint (0, &c->base, 1);
+  install_breakpoint (0, c, 1);
 }
 
 
@@ -473,7 +463,6 @@ initialize_signal_catchpoint_ops (void)
 
   ops = &signal_catchpoint_ops;
   *ops = base_breakpoint_ops;
-  ops->dtor = signal_catchpoint_dtor;
   ops->insert_location = signal_catchpoint_insert_location;
   ops->remove_location = signal_catchpoint_remove_location;
   ops->breakpoint_hit = signal_catchpoint_breakpoint_hit;
diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
index 322f680..92ab91b 100644
--- a/gdb/break-catch-syscall.c
+++ b/gdb/break-catch-syscall.c
@@ -31,15 +31,12 @@
 #include "xml-syscall.h"
 
 /* An instance of this type is used to represent a syscall catchpoint.
-   It includes a "struct breakpoint" as a kind of base class; users
-   downcast to "struct breakpoint *" when needed.  A breakpoint is
-   really of this type iff its ops pointer points to
+   A breakpoint is really of this type iff its ops pointer points to
    CATCH_SYSCALL_BREAKPOINT_OPS.  */
 
-struct syscall_catchpoint
+struct syscall_catchpoint : public breakpoint
 {
-  /* The base class.  */
-  struct breakpoint base;
+  ~syscall_catchpoint () override;
 
   /* Syscall numbers used for the 'catch syscall' feature.  If no
      syscall has been specified for filtering, its value is NULL.
@@ -48,17 +45,11 @@ struct syscall_catchpoint
   VEC(int) *syscalls_to_be_caught;
 };
 
-/* Implement the "dtor" breakpoint_ops method for syscall
-   catchpoints.  */
+/* catch_syscall destructor.  */
 
-static void
-dtor_catch_syscall (struct breakpoint *b)
+syscall_catchpoint::~syscall_catchpoint ()
 {
-  struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
-
-  VEC_free (int, c->syscalls_to_be_caught);
-
-  base_breakpoint_ops.dtor (b);
+  VEC_free (int, this->syscalls_to_be_caught);
 }
 
 static const struct inferior_data *catch_syscall_inferior_data = NULL;
@@ -434,10 +425,10 @@ create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
   struct gdbarch *gdbarch = get_current_arch ();
 
   c = new syscall_catchpoint ();
-  init_catchpoint (&c->base, gdbarch, tempflag, NULL, ops);
+  init_catchpoint (c, gdbarch, tempflag, NULL, ops);
   c->syscalls_to_be_caught = filter;
 
-  install_breakpoint (0, &c->base, 1);
+  install_breakpoint (0, c, 1);
 }
 
 /* Splits the argument using space as delimiter.  Returns an xmalloc'd
@@ -701,7 +692,6 @@ initialize_syscall_catchpoint_ops (void)
   /* Syscall catchpoints.  */
   ops = &catch_syscall_breakpoint_ops;
   *ops = base_breakpoint_ops;
-  ops->dtor = dtor_catch_syscall;
   ops->insert_location = insert_catch_syscall;
   ops->remove_location = remove_catch_syscall;
   ops->breakpoint_hit = breakpoint_hit_catch_syscall;
diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
index 2714bbf..7731c5e 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -74,11 +74,9 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops;
 
 /* The type of an exception catchpoint.  */
 
-struct exception_catchpoint
+struct exception_catchpoint : public breakpoint
 {
-  /* The base class.  */
-
-  struct breakpoint base;
+  ~exception_catchpoint () override;
 
   /* The kind of exception catchpoint.  */
 
@@ -142,17 +140,13 @@ classify_exception_breakpoint (struct breakpoint *b)
   return cp->kind;
 }
 
-/* Implement the 'dtor' method.  */
+/* exception_catchpoint destructor.  */
 
-static void
-dtor_exception_catchpoint (struct breakpoint *self)
+exception_catchpoint::~exception_catchpoint ()
 {
-  struct exception_catchpoint *cp = (struct exception_catchpoint *) self;
-
-  xfree (cp->exception_rx);
-  if (cp->pattern != NULL)
-    regfree (cp->pattern);
-  bkpt_breakpoint_ops.dtor (self);
+  xfree (this->exception_rx);
+  if (this->pattern != NULL)
+    regfree (this->pattern);
 }
 
 /* Implement the 'check_status' method.  */
@@ -396,18 +390,18 @@ handle_gnu_v3_exceptions (int tempflag, char *except_rx,
 
   std::unique_ptr<exception_catchpoint> cp (new exception_catchpoint ());
 
-  init_catchpoint (&cp->base, get_current_arch (), tempflag, cond_string,
+  init_catchpoint (cp.get (), get_current_arch (), tempflag, cond_string,
 		   &gnu_v3_exception_catchpoint_ops);
   /* We need to reset 'type' in order for code in breakpoint.c to do
      the right thing.  */
-  cp->base.type = bp_breakpoint;
+  cp->type = bp_breakpoint;
   cp->kind = ex_event;
   cp->exception_rx = except_rx;
   cp->pattern = pattern;
 
-  re_set_exception_catchpoint (&cp->base);
+  re_set_exception_catchpoint (cp.get ());
 
-  install_breakpoint (0, &cp->base, 1);
+  install_breakpoint (0, cp.get (), 1);
   cp.release ();
 }
 
@@ -558,7 +552,6 @@ initialize_throw_catchpoint_ops (void)
   /* GNU v3 exception catchpoints.  */
   ops = &gnu_v3_exception_catchpoint_ops;
   *ops = bkpt_breakpoint_ops;
-  ops->dtor = dtor_exception_catchpoint;
   ops->re_set = re_set_exception_catchpoint;
   ops->print_it = print_it_exception_catchpoint;
   ops->print_one = print_one_exception_catchpoint;
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 31931e8..0dc9841 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -309,9 +309,6 @@ static struct breakpoint_ops internal_breakpoint_ops;
 /* Momentary breakpoints class type.  */
 static struct breakpoint_ops momentary_breakpoint_ops;
 
-/* Momentary breakpoints for bp_longjmp and bp_exception class type.  */
-static struct breakpoint_ops longjmp_breakpoint_ops;
-
 /* The breakpoint_ops structure to be used in regular user created
    breakpoints.  */
 struct breakpoint_ops bkpt_breakpoint_ops;
@@ -1160,9 +1157,9 @@ check_no_tracepoint_commands (struct command_line *commands)
     }
 }
 
-struct longjmp_breakpoint
+struct longjmp_breakpoint : public breakpoint
 {
-  breakpoint base;
+  ~longjmp_breakpoint () override;
 };
 
 /* Encapsulate tests for different types of tracepoints.  */
@@ -1196,9 +1193,9 @@ new_breakpoint_from_type (bptype type)
   breakpoint *b;
 
   if (is_tracepoint_type (type))
-    b = (breakpoint *) new tracepoint ();
+    b = new tracepoint ();
   else if (is_longjmp_type (type))
-    b = (breakpoint *) new longjmp_breakpoint ();
+    b = new longjmp_breakpoint ();
   else
     b = new breakpoint ();
 
@@ -1736,7 +1733,7 @@ is_watchpoint (const struct breakpoint *bpt)
 static int
 watchpoint_in_thread_scope (struct watchpoint *b)
 {
-  return (b->base.pspace == current_program_space
+  return (b->pspace == current_program_space
 	  && (ptid_equal (b->watchpoint_thread, null_ptid)
 	      || (ptid_equal (inferior_ptid, b->watchpoint_thread)
 		  && !is_executing (inferior_ptid))));
@@ -1748,17 +1745,15 @@ watchpoint_in_thread_scope (struct watchpoint *b)
 static void
 watchpoint_del_at_next_stop (struct watchpoint *w)
 {
-  struct breakpoint *b = &w->base;
-
-  if (b->related_breakpoint != b)
+  if (w->related_breakpoint != w)
     {
-      gdb_assert (b->related_breakpoint->type == bp_watchpoint_scope);
-      gdb_assert (b->related_breakpoint->related_breakpoint == b);
-      b->related_breakpoint->disposition = disp_del_at_next_stop;
-      b->related_breakpoint->related_breakpoint = b->related_breakpoint;
-      b->related_breakpoint = b;
+      gdb_assert (w->related_breakpoint->type == bp_watchpoint_scope);
+      gdb_assert (w->related_breakpoint->related_breakpoint == w);
+      w->related_breakpoint->disposition = disp_del_at_next_stop;
+      w->related_breakpoint->related_breakpoint = w->related_breakpoint;
+      w->related_breakpoint = w;
     }
-  b->disposition = disp_del_at_next_stop;
+  w->disposition = disp_del_at_next_stop;
 }
 
 /* Extract a bitfield value from value VAL using the bit parameters contained in
@@ -1879,7 +1874,7 @@ update_watchpoint (struct watchpoint *b, int reparse)
   if (!watchpoint_in_thread_scope (b))
     return;
 
-  if (b->base.disposition == disp_del_at_next_stop)
+  if (b->disposition == disp_del_at_next_stop)
     return;
  
   frame_saved = 0;
@@ -1917,7 +1912,7 @@ update_watchpoint (struct watchpoint *b, int reparse)
   /* We don't free locations.  They are stored in the bp_location array
      and update_global_location_list will eventually delete them and
      remove breakpoints if needed.  */
-  b->base.loc = NULL;
+  b->loc = NULL;
 
   if (within_current_scope && reparse)
     {
@@ -1937,11 +1932,11 @@ update_watchpoint (struct watchpoint *b, int reparse)
       /* Note that unlike with breakpoints, the watchpoint's condition
 	 expression is stored in the breakpoint object, not in the
 	 locations (re)created below.  */
-      if (b->base.cond_string != NULL)
+      if (b->cond_string != NULL)
 	{
 	  b->cond_exp.reset ();
 
-	  s = b->base.cond_string;
+	  s = b->cond_string;
 	  b->cond_exp = parse_exp_1 (&s, 0, b->cond_exp_valid_block, 0);
 	}
     }
@@ -1958,8 +1953,8 @@ update_watchpoint (struct watchpoint *b, int reparse)
 	 the target gains execution, through breakpoint_re_set.  */
       if (!can_use_hw_watchpoints)
 	{
-	  if (b->base.ops->works_in_software_mode (&b->base))
-	    b->base.type = bp_watchpoint;
+	  if (b->ops->works_in_software_mode (b))
+	    b->type = bp_watchpoint;
 	  else
 	    error (_("Can't set read/access watchpoint when "
 		     "hardware watchpoints are disabled."));
@@ -1979,7 +1974,7 @@ update_watchpoint (struct watchpoint *b, int reparse)
 	 happens, the code that reports it updates b->val directly.
 	 We don't keep track of the memory value for masked
 	 watchpoints.  */
-      if (!b->val_valid && !is_masked_watchpoint (&b->base))
+      if (!b->val_valid && !is_masked_watchpoint (b))
 	{
 	  if (b->val_bitsize != 0)
 	    {
@@ -2042,13 +2037,13 @@ update_watchpoint (struct watchpoint *b, int reparse)
 		    }
 
 		  type = hw_write;
-		  if (b->base.type == bp_read_watchpoint)
+		  if (b->type == bp_read_watchpoint)
 		    type = hw_read;
-		  else if (b->base.type == bp_access_watchpoint)
+		  else if (b->type == bp_access_watchpoint)
 		    type = hw_access;
 
-		  loc = allocate_bp_location (&b->base);
-		  for (tmp = &(b->base.loc); *tmp != NULL; tmp = &((*tmp)->next))
+		  loc = allocate_bp_location (b);
+		  for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
 		    ;
 		  *tmp = loc;
 		  loc->gdbarch = get_type_arch (value_type (v));
@@ -2098,7 +2093,7 @@ update_watchpoint (struct watchpoint *b, int reparse)
 	      /* If this is a software watchpoint, we try to turn it
 		 to a hardware one -- count resources as if B was of
 		 hardware watchpoint type.  */
-	      type = b->base.type;
+	      type = b->type;
 	      if (type == bp_watchpoint)
 		type = bp_hardware_watchpoint;
 
@@ -2109,16 +2104,16 @@ update_watchpoint (struct watchpoint *b, int reparse)
 		 manually.  */
 
 	      /* Count resources used by all watchpoints except B.  */
-	      i = hw_watchpoint_used_count_others (&b->base, type, &other_type_used);
+	      i = hw_watchpoint_used_count_others (b, type, &other_type_used);
 
 	      /* Add in the resources needed for B.  */
-	      i += hw_watchpoint_use_count (&b->base);
+	      i += hw_watchpoint_use_count (b);
 
 	      target_resources_ok
 		= target_can_use_hardware_watchpoint (type, i, other_type_used);
 	      if (target_resources_ok <= 0)
 		{
-		  int sw_mode = b->base.ops->works_in_software_mode (&b->base);
+		  int sw_mode = b->ops->works_in_software_mode (b);
 
 		  if (target_resources_ok == 0 && !sw_mode)
 		    error (_("Target does not support this type of "
@@ -2128,7 +2123,7 @@ update_watchpoint (struct watchpoint *b, int reparse)
 			     "resources for this watchpoint."));
 
 		  /* Downgrade to software watchpoint.  */
-		  b->base.type = bp_watchpoint;
+		  b->type = bp_watchpoint;
 		}
 	      else
 		{
@@ -2136,10 +2131,10 @@ update_watchpoint (struct watchpoint *b, int reparse)
 		     found we have enough resources to turn it to a
 		     hardware watchpoint.  Otherwise, this is a
 		     nop.  */
-		  b->base.type = type;
+		  b->type = type;
 		}
 	    }
-	  else if (!b->base.ops->works_in_software_mode (&b->base))
+	  else if (!b->ops->works_in_software_mode (b))
 	    {
 	      if (!can_use_hw_watchpoints)
 		error (_("Can't set read/access watchpoint when "
@@ -2149,11 +2144,11 @@ update_watchpoint (struct watchpoint *b, int reparse)
 			 "read/access watchpoint."));
 	    }
 	  else
-	    b->base.type = bp_watchpoint;
+	    b->type = bp_watchpoint;
 
-	  loc_type = (b->base.type == bp_watchpoint? bp_loc_other
+	  loc_type = (b->type == bp_watchpoint? bp_loc_other
 		      : bp_loc_hardware_watchpoint);
-	  for (bl = b->base.loc; bl; bl = bl->next)
+	  for (bl = b->loc; bl; bl = bl->next)
 	    bl->loc_type = loc_type;
 	}
 
@@ -2168,15 +2163,15 @@ update_watchpoint (struct watchpoint *b, int reparse)
 	 above left it without any location set up.  But,
 	 bpstat_stop_status requires a location to be able to report
 	 stops, so make sure there's at least a dummy one.  */
-      if (b->base.type == bp_watchpoint && b->base.loc == NULL)
-	software_watchpoint_add_no_memory_location (&b->base, frame_pspace);
+      if (b->type == bp_watchpoint && b->loc == NULL)
+	software_watchpoint_add_no_memory_location (b, frame_pspace);
     }
   else if (!within_current_scope)
     {
       printf_filtered (_("\
 Watchpoint %d deleted because the program has left the block\n\
 in which its expression is valid.\n"),
-		       b->base.number);
+		       b->number);
       watchpoint_del_at_next_stop (b);
     }
 
@@ -5196,7 +5191,7 @@ watchpoint_check (void *p)
       struct value *mark;
       struct value *new_val;
 
-      if (is_masked_watchpoint (&b->base))
+      if (is_masked_watchpoint (b))
 	/* Since we don't know the exact trigger address (from
 	   stopped_data_address), just tell the user we've triggered
 	   a mask watchpoint.  */
@@ -5256,13 +5251,13 @@ watchpoint_check (void *p)
 	    uiout->field_string
 	      ("reason", async_reason_lookup (EXEC_ASYNC_WATCHPOINT_SCOPE));
 	  uiout->text ("\nWatchpoint ");
-	  uiout->field_int ("wpnum", b->base.number);
+	  uiout->field_int ("wpnum", b->number);
 	  uiout->text (" deleted because the program has left the block in\n"
 		       "which its expression is valid.\n");
 	}
 
       /* Make sure the watchpoint's commands aren't executed.  */
-      decref_counted_command_line (&b->base.commands);
+      decref_counted_command_line (&b->commands);
       watchpoint_del_at_next_stop (b);
 
       return WP_DELETED;
@@ -5304,7 +5299,7 @@ bpstat_check_watchpoint (bpstat bs)
     {
       int must_check_value = 0;
       
-      if (b->base.type == bp_watchpoint)
+      if (b->type == bp_watchpoint)
 	/* For a software watchpoint, we must always check the
 	   watched value.  */
 	must_check_value = 1;
@@ -5314,7 +5309,7 @@ bpstat_check_watchpoint (bpstat bs)
 	   this watchpoint.  */
 	must_check_value = 1;
       else if (b->watchpoint_triggered == watch_triggered_unknown
-	       && b->base.type == bp_hardware_watchpoint)
+	       && b->type == bp_hardware_watchpoint)
 	/* We were stopped by a hardware watchpoint, but the target could
 	   not report the data address.  We must check the watchpoint's
 	   value.  Access and read watchpoints are out of luck; without
@@ -5325,7 +5320,7 @@ bpstat_check_watchpoint (bpstat bs)
 	{
 	  char *message
 	    = xstrprintf ("Error evaluating expression for watchpoint %d\n",
-			  b->base.number);
+			  b->number);
 	  struct cleanup *cleanups = make_cleanup (xfree, message);
 	  int e = catch_errors (watchpoint_check, bs, message,
 				RETURN_MASK_ALL);
@@ -5342,7 +5337,7 @@ bpstat_check_watchpoint (bpstat bs)
 	      bs->stop = 0;
 	      break;
 	    case WP_VALUE_CHANGED:
-	      if (b->base.type == bp_read_watchpoint)
+	      if (b->type == bp_read_watchpoint)
 		{
 		  /* There are two cases to consider here:
 
@@ -5413,8 +5408,8 @@ bpstat_check_watchpoint (bpstat bs)
 		}
 	      break;
 	    case WP_VALUE_NOT_CHANGED:
-	      if (b->base.type == bp_hardware_watchpoint
-		  || b->base.type == bp_watchpoint)
+	      if (b->type == bp_hardware_watchpoint
+		  || b->type == bp_watchpoint)
 		{
 		  /* Don't stop: write watchpoints shouldn't fire if
 		     the value hasn't changed.  */
@@ -5431,7 +5426,7 @@ bpstat_check_watchpoint (bpstat bs)
 		SWITCH_THRU_ALL_UIS ()
 	          {
 		    printf_filtered (_("Watchpoint %d deleted.\n"),
-				     b->base.number);
+				     b->number);
 		  }
 		watchpoint_del_at_next_stop (b);
 		/* We've already printed what needs to be printed.  */
@@ -7609,7 +7604,7 @@ set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame)
 	/* longjmp_breakpoint_ops ensures INITIATING_FRAME is cleared again
 	   after their removal.  */
 	clone = momentary_breakpoint_from_master (b, type,
-						  &longjmp_breakpoint_ops, 1);
+						  &momentary_breakpoint_ops, 1);
 	clone->thread = thread;
       }
 
@@ -8031,16 +8026,11 @@ disable_breakpoints_in_freed_objfile (struct objfile *objfile)
 /* FORK & VFORK catchpoints.  */
 
 /* An instance of this type is used to represent a fork or vfork
-   catchpoint.  It includes a "struct breakpoint" as a kind of base
-   class; users downcast to "struct breakpoint *" when needed.  A
-   breakpoint is really of this type iff its ops pointer points to
-   CATCH_FORK_BREAKPOINT_OPS.  */
+   catchpoint.  A breakpoint is really of this type iff its ops pointer points
+   to CATCH_FORK_BREAKPOINT_OPS.  */
 
-struct fork_catchpoint
+struct fork_catchpoint : public breakpoint
 {
-  /* The base class.  */
-  struct breakpoint base;
-
   /* Process id of a child process whose forking triggered this
      catchpoint.  This field is only valid immediately after this
      catchpoint has triggered.  */
@@ -8279,15 +8269,12 @@ print_recreate_catch_vfork (struct breakpoint *b, struct ui_file *fp)
 static struct breakpoint_ops catch_vfork_breakpoint_ops;
 
 /* An instance of this type is used to represent an solib catchpoint.
-   It includes a "struct breakpoint" as a kind of base class; users
-   downcast to "struct breakpoint *" when needed.  A breakpoint is
-   really of this type iff its ops pointer points to
+   A breakpoint is really of this type iff its ops pointer points to
    CATCH_SOLIB_BREAKPOINT_OPS.  */
 
-struct solib_catchpoint
+struct solib_catchpoint : public breakpoint
 {
-  /* The base class.  */
-  struct breakpoint base;
+  ~solib_catchpoint () override;
 
   /* True for "catch load", false for "catch unload".  */
   unsigned char is_load;
@@ -8298,16 +8285,11 @@ struct solib_catchpoint
   regex_t compiled;
 };
 
-static void
-dtor_catch_solib (struct breakpoint *b)
+solib_catchpoint::~solib_catchpoint ()
 {
-  struct solib_catchpoint *self = (struct solib_catchpoint *) b;
-
-  if (self->regex)
-    regfree (&self->compiled);
-  xfree (self->regex);
-
-  base_breakpoint_ops.dtor (b);
+  if (this->regex)
+    regfree (&this->compiled);
+  xfree (this->regex);
 }
 
 static int
@@ -8344,7 +8326,7 @@ breakpoint_hit_catch_solib (const struct bp_location *bl,
     if (other->type != bp_shlib_event)
       continue;
 
-    if (self->base.pspace != NULL && other->pspace != self->base.pspace)
+    if (self->pspace != NULL && other->pspace != self->pspace)
       continue;
 
     for (other_bl = other->loc; other_bl != NULL; other_bl = other_bl->next)
@@ -8518,13 +8500,13 @@ add_solib_catchpoint (const char *arg, int is_load, int is_temp, int enabled)
     }
 
   c->is_load = is_load;
-  init_catchpoint (&c->base, gdbarch, is_temp, NULL,
+  init_catchpoint (c, gdbarch, is_temp, NULL,
 		   &catch_solib_breakpoint_ops);
 
-  c->base.enable_state = enabled ? bp_enabled : bp_disabled;
+  c->enable_state = enabled ? bp_enabled : bp_disabled;
 
   discard_cleanups (cleanup);
-  install_breakpoint (0, &c->base, 1);
+  install_breakpoint (0, c, 1);
 }
 
 /* A helper function that does all the work for "catch load" and
@@ -8600,25 +8582,22 @@ create_fork_vfork_event_catchpoint (struct gdbarch *gdbarch,
 {
   struct fork_catchpoint *c = new fork_catchpoint ();
 
-  init_catchpoint (&c->base, gdbarch, tempflag, cond_string, ops);
+  init_catchpoint (c, gdbarch, tempflag, cond_string, ops);
 
   c->forked_inferior_pid = null_ptid;
 
-  install_breakpoint (0, &c->base, 1);
+  install_breakpoint (0, c, 1);
 }
 
 /* Exec catchpoints.  */
 
 /* An instance of this type is used to represent an exec catchpoint.
-   It includes a "struct breakpoint" as a kind of base class; users
-   downcast to "struct breakpoint *" when needed.  A breakpoint is
-   really of this type iff its ops pointer points to
+   A breakpoint is really of this type iff its ops pointer points to
    CATCH_EXEC_BREAKPOINT_OPS.  */
 
-struct exec_catchpoint
+struct exec_catchpoint : public breakpoint
 {
-  /* The base class.  */
-  struct breakpoint base;
+  ~exec_catchpoint () override;
 
   /* Filename of a program whose exec triggered this catchpoint.
      This field is only valid immediately after this catchpoint has
@@ -8626,17 +8605,11 @@ struct exec_catchpoint
   char *exec_pathname;
 };
 
-/* Implement the "dtor" breakpoint_ops method for exec
-   catchpoints.  */
+/* Exec catchpoint destructor.  */
 
-static void
-dtor_catch_exec (struct breakpoint *b)
+exec_catchpoint::~exec_catchpoint ()
 {
-  struct exec_catchpoint *c = (struct exec_catchpoint *) b;
-
-  xfree (c->exec_pathname);
-
-  base_breakpoint_ops.dtor (b);
+  xfree (this->exec_pathname);
 }
 
 static int
@@ -10510,18 +10483,13 @@ watchpoint_exp_is_const (const struct expression *exp)
   return 1;
 }
 
-/* Implement the "dtor" breakpoint_ops method for watchpoints.  */
+/* Watchpoint destructor.  */
 
-static void
-dtor_watchpoint (struct breakpoint *self)
+watchpoint::~watchpoint ()
 {
-  struct watchpoint *w = (struct watchpoint *) self;
-
-  xfree (w->exp_string);
-  xfree (w->exp_string_reparse);
-  value_free (w->val);
-
-  base_breakpoint_ops.dtor (self);
+  xfree (this->exp_string);
+  xfree (this->exp_string_reparse);
+  value_free (this->val);
 }
 
 /* Implement the "re_set" breakpoint_ops method for watchpoints.  */
@@ -11006,7 +10974,7 @@ static void
 watch_command_1 (const char *arg, int accessflag, int from_tty,
 		 int just_location, int internal)
 {
-  struct breakpoint *b, *scope_breakpoint = NULL;
+  struct breakpoint *scope_breakpoint = NULL;
   const struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
   struct value *val, *mark, *result;
   int saved_bitpos = 0, saved_bitsize = 0;
@@ -11245,16 +11213,16 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
     bp_type = bp_hardware_watchpoint;
 
   w = new watchpoint ();
-  b = &w->base;
+
   if (use_mask)
-    init_raw_breakpoint_without_location (b, NULL, bp_type,
+    init_raw_breakpoint_without_location (w, NULL, bp_type,
 					  &masked_watchpoint_breakpoint_ops);
   else
-    init_raw_breakpoint_without_location (b, NULL, bp_type,
+    init_raw_breakpoint_without_location (w, NULL, bp_type,
 					  &watchpoint_breakpoint_ops);
-  b->thread = thread;
-  b->disposition = disp_donttouch;
-  b->pspace = current_program_space;
+  w->thread = thread;
+  w->disposition = disp_donttouch;
+  w->pspace = current_program_space;
   w->exp = std::move (exp);
   w->exp_valid_block = exp_valid_block;
   w->cond_exp_valid_block = cond_exp_valid_block;
@@ -11285,9 +11253,9 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
     }
 
   if (cond_start)
-    b->cond_string = savestring (cond_start, cond_end - cond_start);
+    w->cond_string = savestring (cond_start, cond_end - cond_start);
   else
-    b->cond_string = 0;
+    w->cond_string = 0;
 
   if (frame_id_p (watchpoint_frame))
     {
@@ -11304,8 +11272,8 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
     {
       /* The scope breakpoint is related to the watchpoint.  We will
 	 need to act on them together.  */
-      b->related_breakpoint = scope_breakpoint;
-      scope_breakpoint->related_breakpoint = b;
+      w->related_breakpoint = scope_breakpoint;
+      scope_breakpoint->related_breakpoint = w;
     }
 
   if (!just_location)
@@ -11319,12 +11287,12 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
     }
   CATCH (e, RETURN_MASK_ALL)
     {
-      delete_breakpoint (b);
+      delete_breakpoint (w);
       throw_exception (e);
     }
   END_CATCH
 
-  install_breakpoint (internal, b, 1);
+  install_breakpoint (internal, w, 1);
   do_cleanups (back_to);
 }
 
@@ -11794,11 +11762,11 @@ catch_exec_command_1 (char *arg_entry, int from_tty,
     error (_("Junk at end of arguments."));
 
   c = new exec_catchpoint ();
-  init_catchpoint (&c->base, gdbarch, tempflag, cond_string,
+  init_catchpoint (c, gdbarch, tempflag, cond_string,
 		   &catch_exec_breakpoint_ops);
   c->exec_pathname = NULL;
 
-  install_breakpoint (0, &c->base, 1);
+  install_breakpoint (0, c, 1);
 }
 
 void
@@ -12763,16 +12731,14 @@ static const struct bp_location_ops bp_location_ops =
   bp_location_dtor
 };
 
-/* Default breakpoint_ops methods all breakpoint_ops ultimately
-   inherit from.  */
+/* Destructor for the breakpoint base class.  */
 
-static void
-base_breakpoint_dtor (struct breakpoint *self)
+breakpoint::~breakpoint ()
 {
-  decref_counted_command_line (&self->commands);
-  xfree (self->cond_string);
-  xfree (self->extra_string);
-  xfree (self->filter);
+  decref_counted_command_line (&this->commands);
+  xfree (this->cond_string);
+  xfree (this->extra_string);
+  xfree (this->filter);
 }
 
 static struct bp_location *
@@ -12913,7 +12879,6 @@ base_breakpoint_after_condition_true (struct bpstats *bs)
 
 struct breakpoint_ops base_breakpoint_ops =
 {
-  base_breakpoint_dtor,
   base_breakpoint_allocate_location,
   base_breakpoint_re_set,
   base_breakpoint_insert_location,
@@ -13281,15 +13246,12 @@ momentary_bkpt_print_mention (struct breakpoint *b)
    It gets cleared already on the removal of the first one of such placed
    breakpoints.  This is OK as they get all removed altogether.  */
 
-static void
-longjmp_bkpt_dtor (struct breakpoint *self)
+longjmp_breakpoint::~longjmp_breakpoint ()
 {
-  struct thread_info *tp = find_thread_global_id (self->thread);
+  thread_info *tp = find_thread_global_id (this->thread);
 
-  if (tp)
+  if (tp != NULL)
     tp->initiating_frame = null_frame_id;
-
-  momentary_breakpoint_ops.dtor (self);
 }
 
 /* Specific methods for probe breakpoints.  */
@@ -13634,7 +13596,7 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
       location = copy_event_location (canonical->location.get ());
 
       tp = new tracepoint ();
-      init_breakpoint_sal (&tp->base, gdbarch, expanded,
+      init_breakpoint_sal (tp, gdbarch, expanded,
 			   std::move (location), NULL,
 			   cond_string, extra_string,
 			   type_wanted, disposition,
@@ -13649,7 +13611,7 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch,
 	 corresponds to this one  */
       tp->static_trace_marker_id_idx = i;
 
-      install_breakpoint (internal, &tp->base, 0);
+      install_breakpoint (internal, tp, 0);
     }
 }
 
@@ -13769,7 +13731,6 @@ delete_breakpoint (struct breakpoint *bpt)
      self-contained, but it's not the case now.  */
   update_global_location_list (UGLL_DONT_INSERT);
 
-  bpt->ops->dtor (bpt);
   /* On the chance that someone will soon try again to delete this
      same bp, we mark it as deleted before freeing its storage.  */
   bpt->type = bp_none;
@@ -15265,7 +15226,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
   if (utp->pass > 0)
     {
       xsnprintf (small_buf, sizeof (small_buf), "%d %d", utp->pass,
-		 tp->base.number);
+		 tp->number);
 
       trace_pass_command (small_buf, 0);
     }
@@ -15283,7 +15244,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
 
       cmd_list = read_command_lines_1 (read_uploaded_action, 1, NULL, NULL);
 
-      breakpoint_set_commands (&tp->base, std::move (cmd_list));
+      breakpoint_set_commands (tp, std::move (cmd_list));
     }
   else if (!VEC_empty (char_ptr, utp->actions)
 	   || !VEC_empty (char_ptr, utp->step_actions))
@@ -15292,7 +15253,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
 	     utp->number);
 
   /* Copy any status information that might be available.  */
-  tp->base.hit_count = utp->hit_count;
+  tp->hit_count = utp->hit_count;
   tp->traceframe_usage = utp->traceframe_usage;
 
   return tp;
@@ -15378,10 +15339,10 @@ static void
 trace_pass_set_count (struct tracepoint *tp, int count, int from_tty)
 {
   tp->pass_count = count;
-  observer_notify_breakpoint_modified (&tp->base);
+  observer_notify_breakpoint_modified (tp);
   if (from_tty)
     printf_filtered (_("Setting tracepoint %d's passcount to %d\n"),
-		     tp->base.number, count);
+		     tp->number, count);
 }
 
 /* Set passcount for tracepoint.
@@ -15887,11 +15848,6 @@ initialize_breakpoint_ops (void)
   ops->print_it = momentary_bkpt_print_it;
   ops->print_mention = momentary_bkpt_print_mention;
 
-  /* Momentary breakpoints for bp_longjmp and bp_exception.  */
-  ops = &longjmp_breakpoint_ops;
-  *ops = momentary_breakpoint_ops;
-  ops->dtor = longjmp_bkpt_dtor;
-
   /* Probe breakpoints.  */
   ops = &bkpt_probe_breakpoint_ops;
   *ops = bkpt_breakpoint_ops;
@@ -15903,7 +15859,6 @@ initialize_breakpoint_ops (void)
   /* Watchpoints.  */
   ops = &watchpoint_breakpoint_ops;
   *ops = base_breakpoint_ops;
-  ops->dtor = dtor_watchpoint;
   ops->re_set = re_set_watchpoint;
   ops->insert_location = insert_watchpoint;
   ops->remove_location = remove_watchpoint;
@@ -15978,7 +15933,6 @@ initialize_breakpoint_ops (void)
   /* Exec catchpoints.  */
   ops = &catch_exec_breakpoint_ops;
   *ops = base_breakpoint_ops;
-  ops->dtor = dtor_catch_exec;
   ops->insert_location = insert_catch_exec;
   ops->remove_location = remove_catch_exec;
   ops->breakpoint_hit = breakpoint_hit_catch_exec;
@@ -15990,7 +15944,6 @@ initialize_breakpoint_ops (void)
   /* Solib-related catchpoints.  */
   ops = &catch_solib_breakpoint_ops;
   *ops = base_breakpoint_ops;
-  ops->dtor = dtor_catch_solib;
   ops->insert_location = insert_catch_solib;
   ops->remove_location = remove_catch_solib;
   ops->breakpoint_hit = breakpoint_hit_catch_solib;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 26b0aa5..848d2c6 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -512,10 +512,6 @@ enum print_stop_action
 
 struct breakpoint_ops
 {
-  /* Destructor.  Releases everything from SELF (but not SELF
-     itself).  */
-  void (*dtor) (struct breakpoint *self);
-
   /* Allocate a location for this breakpoint.  */
   struct bp_location * (*allocate_location) (struct breakpoint *);
 
@@ -680,6 +676,8 @@ extern int target_exact_watchpoints;
 
 struct breakpoint
 {
+  virtual ~breakpoint ();
+
   /* Methods associated with this breakpoint.  */
   const breakpoint_ops *ops = NULL;
 
@@ -783,14 +781,11 @@ struct breakpoint
   gdbscm_breakpoint_object *scm_bp_object = NULL;
 };
 
-/* An instance of this type is used to represent a watchpoint.  It
-   includes a "struct breakpoint" as a kind of base class; users
-   downcast to "struct breakpoint *" when needed.  */
+/* An instance of this type is used to represent a watchpoint.  */
 
-struct watchpoint
+struct watchpoint : public breakpoint
 {
-  /* The base class.  */
-  struct breakpoint base;
+  ~watchpoint () override;
 
   /* String form of exp to use for displaying to the user (malloc'd),
      or NULL if none.  */
@@ -867,14 +862,10 @@ extern int is_breakpoint (const struct breakpoint *bpt);
 extern int is_watchpoint (const struct breakpoint *bpt);
 
 /* An instance of this type is used to represent all kinds of
-   tracepoints.  It includes a "struct breakpoint" as a kind of base
-   class; users downcast to "struct breakpoint *" when needed.  */
+   tracepoints.  */
 
-struct tracepoint
+struct tracepoint : public breakpoint
 {
-  /* The base class.  */
-  struct breakpoint base;
-
   /* Number of times this tracepoint should single-step and collect
      additional data.  */
   long step_count;
diff --git a/gdb/ctf.c b/gdb/ctf.c
index 8716cad..82e7013 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -1522,8 +1522,8 @@ ctf_get_traceframe_address (void)
       struct tracepoint *tp
 	= get_tracepoint_by_number_on_target (tpnum);
 
-      if (tp && tp->base.loc)
-	addr = tp->base.loc->address;
+      if (tp && tp->loc)
+	addr = tp->loc->address;
     }
 
   /* Restore the position.  */
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index cfe2d34..9412af8 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -398,7 +398,7 @@ mi_cmd_break_passcount (const char *command, char **argv, int argc)
   if (t)
     {
       t->pass_count = p;
-      observer_notify_breakpoint_modified (&t->base);
+      observer_notify_breakpoint_modified (t);
     }
   else
     {
diff --git a/gdb/remote.c b/gdb/remote.c
index de52ac3..1f86079 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -12650,9 +12650,9 @@ remote_get_tracepoint_status (struct target_ops *self, struct breakpoint *bp,
 
   if (tp)
     {
-      tp->base.hit_count = 0;
+      tp->hit_count = 0;
       tp->traceframe_usage = 0;
-      for (loc = tp->base.loc; loc; loc = loc->next)
+      for (loc = tp->loc; loc; loc = loc->next)
 	{
 	  /* If the tracepoint was never downloaded, don't go asking for
 	     any status.  */
diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c
index 255bbc9..d479cef 100644
--- a/gdb/tracefile-tfile.c
+++ b/gdb/tracefile-tfile.c
@@ -650,8 +650,8 @@ tfile_get_traceframe_address (off_t tframe_offset)
 
   tp = get_tracepoint_by_number_on_target (tpnum);
   /* FIXME this is a poor heuristic if multiple locations.  */
-  if (tp && tp->base.loc)
-    addr = tp->base.loc->address;
+  if (tp && tp->loc)
+    addr = tp->loc->address;
 
   /* Restore our seek position.  */
   cur_offset = saved_offset;
diff --git a/gdb/tracefile.c b/gdb/tracefile.c
index cc90945..e208fc6 100644
--- a/gdb/tracefile.c
+++ b/gdb/tracefile.c
@@ -398,15 +398,15 @@ tracefile_fetch_registers (struct regcache *regcache, int regno)
 
   /* We can often usefully guess that the PC is going to be the same
      as the address of the tracepoint.  */
-  if (tp == NULL || tp->base.loc == NULL)
+  if (tp == NULL || tp->loc == NULL)
     return;
 
   /* But don't try to guess if tracepoint is multi-location...  */
-  if (tp->base.loc->next)
+  if (tp->loc->next)
     {
       warning (_("Tracepoint %d has multiple "
 		 "locations, cannot infer $pc"),
-	       tp->base.number);
+	       tp->number);
       return;
     }
   /* ... or does while-stepping.  */
@@ -414,13 +414,13 @@ tracefile_fetch_registers (struct regcache *regcache, int regno)
     {
       warning (_("Tracepoint %d does while-stepping, "
 		 "cannot infer $pc"),
-	       tp->base.number);
+	       tp->number);
       return;
     }
 
   /* Guess what we can from the tracepoint location.  */
   gdbarch_guess_tracepoint_registers (gdbarch, regcache,
-				      tp->base.loc->address);
+				      tp->loc->address);
 }
 
 /* This is the implementation of target_ops method to_has_all_memory.  */
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 98213cf..4f2bac5 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -648,11 +648,11 @@ actions_command (char *args, int from_tty)
     {
       std::string tmpbuf =
 	string_printf ("Enter actions for tracepoint %d, one per line.",
-		       t->base.number);
+		       t->number);
 
       command_line_up l = read_command_lines (&tmpbuf[0], from_tty, 1,
 					      check_tracepoint_command, t);
-      breakpoint_set_commands (&t->base, std::move (l));
+      breakpoint_set_commands (t, std::move (l));
     }
   /* else just return */
 }
@@ -738,7 +738,7 @@ validate_actionline (const char *line, struct breakpoint *b)
 	      /* else fall thru, treat p as an expression and parse it!  */
 	    }
 	  tmp_p = p;
-	  for (loc = t->base.loc; loc; loc = loc->next)
+	  for (loc = t->loc; loc; loc = loc->next)
 	    {
 	      p = tmp_p;
 	      expression_up exp = parse_exp_1 (&p, loc->address,
@@ -788,7 +788,7 @@ validate_actionline (const char *line, struct breakpoint *b)
 	  p = skip_spaces_const (p);
 
 	  tmp_p = p;
-	  for (loc = t->base.loc; loc; loc = loc->next)
+	  for (loc = t->loc; loc; loc = loc->next)
 	    {
 	      p = tmp_p;
 
@@ -2246,7 +2246,7 @@ tfind_1 (enum trace_find_type type, int num,
   reinit_frame_cache ();
   target_dcache_invalidate ();
 
-  set_tracepoint_num (tp ? tp->base.number : target_tracept);
+  set_tracepoint_num (tp ? tp->number : target_tracept);
 
   if (target_frameno != get_traceframe_number ())
     observer_notify_traceframe_changed (target_frameno, tracepoint_number);
@@ -2870,7 +2870,7 @@ get_traceframe_location (int *stepping_frame_p)
      locations, assume it is a direct hit rather than a while-stepping
      frame.  (FIXME this is not reliable, should record each frame's
      type.)  */
-  for (tloc = t->base.loc; tloc; tloc = tloc->next)
+  for (tloc = t->loc; tloc; tloc = tloc->next)
     if (tloc->address == regcache_read_pc (regcache))
       {
 	*stepping_frame_p = 0;
@@ -2880,7 +2880,7 @@ get_traceframe_location (int *stepping_frame_p)
   /* If this is a stepping frame, we don't know which location
      triggered.  The first is as good (or bad) a guess as any...  */
   *stepping_frame_p = 1;
-  return t->base.loc;
+  return t->loc;
 }
 
 /* Return all the actions, including default collect, of a tracepoint
@@ -3231,7 +3231,7 @@ find_matching_tracepoint_location (struct uploaded_tp *utp)
       if (b->type == utp->type
 	  && t->step_count == utp->step
 	  && t->pass_count == utp->pass
-	  && cond_string_is_same (t->base.cond_string, utp->cond_string)
+	  && cond_string_is_same (t->cond_string, utp->cond_string)
 	  /* FIXME also test actions.  */
 	  )
 	{
@@ -3300,7 +3300,7 @@ merge_uploaded_tracepoints (struct uploaded_tp **uploaded_tps)
 	  if (t)
 	    printf_filtered (_("Created tracepoint %d for "
 			       "target's tracepoint %d at %s.\n"),
-			     t->base.number, utp->number,
+			     t->number, utp->number,
 			     paddress (get_current_arch (), utp->addr));
 	  else
 	    printf_filtered (_("Failed to create tracepoint for target's "
@@ -3603,7 +3603,7 @@ parse_tracepoint_status (char *p, struct breakpoint *bp,
 
   p = unpack_varlen_hex (p, &uval);
   if (tp)
-    tp->base.hit_count += uval;
+    tp->hit_count += uval;
   else
     utp->hit_count += uval;
   p = unpack_varlen_hex (p + 1, &uval);
