Introduce ConcreteClusterPath. (#14927)

Will be useful in places where we just need an endpoint+cluster.

Fixes https://github.com/project-chip/connectedhomeip/issues/14820
diff --git a/src/app/ConcreteAttributePath.h b/src/app/ConcreteAttributePath.h
index 0fb764e..97e29bc 100644
--- a/src/app/ConcreteAttributePath.h
+++ b/src/app/ConcreteAttributePath.h
@@ -18,6 +18,7 @@
 
 #pragma once
 
+#include <app/ConcreteClusterPath.h>
 #include <app/util/basic-types.h>
 #include <lib/core/Optional.h>
 
@@ -30,28 +31,34 @@
  * The expanded flag can be set to indicate that a concrete path was expanded from a wildcard
  * or group path.
  */
-struct ConcreteAttributePath
+struct ConcreteAttributePath : public ConcreteClusterPath
 {
-    ConcreteAttributePath() {}
+    ConcreteAttributePath()
+    {
+        // Note: mExpanded is in the superclass, so we can't use a field
+        // initializer.
+        mExpanded = false;
+    }
 
     ConcreteAttributePath(EndpointId aEndpointId, ClusterId aClusterId, AttributeId aAttributeId) :
-        mEndpointId(aEndpointId), mClusterId(aClusterId), mAttributeId(aAttributeId)
-    {}
-
-    bool operator==(const ConcreteAttributePath & other) const
+        ConcreteClusterPath(aEndpointId, aClusterId), mAttributeId(aAttributeId)
     {
-        return (mEndpointId == other.mEndpointId) && (mClusterId == other.mClusterId) && (mAttributeId == other.mAttributeId);
+        // Note: mExpanded is in the supercclass, so we can't use a field
+        // initializer.
+        mExpanded = false;
+    }
+
+    bool operator==(const ConcreteAttributePath & aOther) const
+    {
+        return ConcreteClusterPath::operator==(aOther) && (mAttributeId == aOther.mAttributeId);
     }
 
     bool operator<(const ConcreteAttributePath & path) const
     {
         return (mEndpointId < path.mEndpointId) || ((mEndpointId == path.mEndpointId) && (mClusterId < path.mClusterId)) ||
-            ((mClusterId == path.mClusterId) && (mAttributeId < path.mAttributeId));
+            ((mEndpointId == path.mEndpointId) && (mClusterId == path.mClusterId) && (mAttributeId < path.mAttributeId));
     }
 
-    EndpointId mEndpointId   = 0;
-    bool mExpanded           = false; // NOTE: in between larger members
-    ClusterId mClusterId     = 0;
     AttributeId mAttributeId = 0;
 };