Parent Class with References to Child Class
Description
Parent Class with References to Child Class occurs when a parent class contains a reference or pointer to a child class, either directly or indirectly through another class. This creates a circular dependency between the parent and child classes, violating the principle of modularity and proper inheritance hierarchies. A parent class should be completely unaware of its children, as children extend the parent - not the other way around. This anti-pattern makes the codebase harder to maintain, extend, and test.
Risk
While primarily a code quality issue, this pattern creates indirect security risks. The circular dependency makes it difficult to properly audit security controls, as changes in child classes can unexpectedly affect parent behavior. Unit testing becomes complicated, potentially leading to inadequate security testing coverage. The tight coupling makes it harder to replace or upgrade security-critical components. Code refactoring becomes risky, and developers may avoid necessary security improvements due to the complexity. The pattern also violates SOLID principles (Open/Closed, Dependency Inversion), making the codebase more fragile.
Solution
Apply the Dependency Inversion Principle - high-level modules should not depend on low-level modules, both should depend on abstractions. Use interfaces or abstract classes to define contracts that child classes implement. Apply the factory pattern or dependency injection to create instances without direct references. Refactor common functionality needed by both parent and child into separate utility classes. Use event-driven architectures or observer patterns when parent classes need to respond to child class actions. Conduct regular code reviews focused on dependency direction.
Common Consequences
| Impact | Details |
|---|---|
| Other | Scope: Other Reduce Maintainability - Circular dependencies make the codebase harder to understand, test, and modify safely. |
| Other | Scope: Other Quality Degradation - Tight coupling leads to fragile code where changes have unexpected ripple effects. |
| Other | Scope: Other Reduce Reliability - Testing becomes more difficult, potentially leaving bugs and vulnerabilities undetected. |
Example Code
Vulnerable Code
// Vulnerable: Parent class references child class directly
public class VulnerableBaseDocument {
protected String content;
protected String author;
// Vulnerable: Parent knows about specific child class!
public VulnerablePDFDocument convertToPDF() {
// Parent class creates and returns a child class instance
VulnerablePDFDocument pdf = new VulnerablePDFDocument();
pdf.setContent(this.content);
pdf.setAuthor(this.author);
pdf.generatePDF();
return pdf;
}
// Vulnerable: Another reference to child class
public VulnerableWordDocument convertToWord() {
VulnerableWordDocument word = new VulnerableWordDocument();
word.setContent(this.content);
word.setAuthor(this.author);
return word;
}
// Vulnerable: Type checking for child classes
public void process(VulnerableBaseDocument doc) {
if (doc instanceof VulnerablePDFDocument) {
((VulnerablePDFDocument) doc).compress();
} else if (doc instanceof VulnerableWordDocument) {
((VulnerableWordDocument) doc).applyStyles();
}
}
}
// Child classes
public class VulnerablePDFDocument extends VulnerableBaseDocument {
public void generatePDF() { /* ... */ }
public void compress() { /* ... */ }
}
public class VulnerableWordDocument extends VulnerableBaseDocument {
public void applyStyles() { /* ... */ }
}
// Problems:
// 1. Adding new document types requires modifying parent class
// 2. Parent class is tightly coupled to all children
// 3. Violates Open/Closed Principle
# Vulnerable: Parent class with child class imports
class VulnerableAnimal:
def __init__(self, name):
self.name = name
# Vulnerable: Parent creates child instances
def create_offspring(self, offspring_type):
# Direct reference to child classes in parent
if offspring_type == "dog":
from animals import VulnerableDog # Circular import!
return VulnerableDog(f"{self.name}'s puppy")
elif offspring_type == "cat":
from animals import VulnerableCat # Circular import!
return VulnerableCat(f"{self.name}'s kitten")
else:
raise ValueError(f"Unknown type: {offspring_type}")
# Vulnerable: Type-specific logic in parent
def get_sound(self):
from animals import VulnerableDog, VulnerableCat
if isinstance(self, VulnerableDog):
return "Woof!"
elif isinstance(self, VulnerableCat):
return "Meow!"
return "Unknown"
# In animals.py
class VulnerableDog(VulnerableAnimal):
def bark(self):
print("Woof!")
class VulnerableCat(VulnerableAnimal):
def meow(self):
print("Meow!")
// Vulnerable: C++ parent with forward declaration of child
// Forward declaration doesn't solve the design problem
class VulnerableConcreteHandler; // Child class forward declared
class VulnerableBaseHandler {
protected:
std::string handlerName;
public:
// Vulnerable: Returns pointer to child class
virtual VulnerableConcreteHandler* getConcreteHandler() {
// Parent knows about and creates child
return new VulnerableConcreteHandler();
}
// Vulnerable: Static method referencing child
static VulnerableBaseHandler* createHandler(const std::string& type) {
if (type == "concrete") {
return new VulnerableConcreteHandler();
}
return new VulnerableBaseHandler();
}
};
class VulnerableConcreteHandler : public VulnerableBaseHandler {
public:
void handleSpecific() {
// Child-specific logic
}
};
Fixed Code
// Fixed: Using interfaces and factory pattern
public abstract class FixedBaseDocument {
protected String content;
protected String author;
public abstract String getFormat();
// Fixed: No references to child classes
// Conversion handled by separate converter classes
public String getContent() {
return content;
}
public String getAuthor() {
return author;
}
public void setContent(String content) {
this.content = content;
}
public void setAuthor(String author) {
this.author = author;
}
}
// Fixed: Child classes are independent
public class FixedPDFDocument extends FixedBaseDocument {
@Override
public String getFormat() {
return "PDF";
}
public void generatePDF() { /* ... */ }
public void compress() { /* ... */ }
}
public class FixedWordDocument extends FixedBaseDocument {
@Override
public String getFormat() {
return "DOCX";
}
public void applyStyles() { /* ... */ }
}
// Fixed: Factory pattern for document creation
public interface DocumentFactory {
FixedBaseDocument createDocument();
}
public class PDFDocumentFactory implements DocumentFactory {
@Override
public FixedBaseDocument createDocument() {
return new FixedPDFDocument();
}
}
// Fixed: Converter interface for format conversion
public interface DocumentConverter<T extends FixedBaseDocument> {
T convert(FixedBaseDocument source);
}
public class PDFConverter implements DocumentConverter<FixedPDFDocument> {
@Override
public FixedPDFDocument convert(FixedBaseDocument source) {
FixedPDFDocument pdf = new FixedPDFDocument();
pdf.setContent(source.getContent());
pdf.setAuthor(source.getAuthor());
pdf.generatePDF();
return pdf;
}
}
// Fixed: Processor using visitor pattern
public interface DocumentVisitor {
void visit(FixedPDFDocument pdf);
void visit(FixedWordDocument word);
}
public class DocumentProcessor implements DocumentVisitor {
@Override
public void visit(FixedPDFDocument pdf) {
pdf.compress();
}
@Override
public void visit(FixedWordDocument word) {
word.applyStyles();
}
}
# Fixed: Using abstract base class and factory pattern
from abc import ABC, abstractmethod
from typing import Dict, Type, Callable
class FixedAnimal(ABC):
def __init__(self, name: str):
self.name = name
@abstractmethod
def get_sound(self) -> str:
"""Each animal implements its own sound"""
pass
# Fixed: No references to child classes
# Offspring creation delegated to factory
class FixedDog(FixedAnimal):
def get_sound(self) -> str:
return "Woof!"
def bark(self):
print(self.get_sound())
class FixedCat(FixedAnimal):
def get_sound(self) -> str:
return "Meow!"
def meow(self):
print(self.get_sound())
# Fixed: Factory pattern in separate module
class AnimalFactory:
"""Factory for creating animals - keeps parent unaware of children"""
_registry: Dict[str, Type[FixedAnimal]] = {}
@classmethod
def register(cls, animal_type: str, animal_class: Type[FixedAnimal]):
cls._registry[animal_type] = animal_class
@classmethod
def create(cls, animal_type: str, name: str) -> FixedAnimal:
if animal_type not in cls._registry:
raise ValueError(f"Unknown animal type: {animal_type}")
return cls._registry[animal_type](name)
# Registration happens in application setup, not in parent class
AnimalFactory.register("dog", FixedDog)
AnimalFactory.register("cat", FixedCat)
# Usage
animal = AnimalFactory.create("dog", "Buddy")
print(animal.get_sound()) # "Woof!"
// Fixed: C++ with proper abstraction
#include <memory>
#include <string>
#include <functional>
#include <map>
// Fixed: Abstract base class with no child references
class FixedBaseHandler {
protected:
std::string handlerName;
public:
virtual ~FixedBaseHandler() = default;
virtual void handle() = 0;
virtual std::string getType() const = 0;
// Fixed: No factory methods in base class
// No references to derived classes
};
// Fixed: Concrete implementations
class FixedConcreteHandler : public FixedBaseHandler {
public:
void handle() override {
// Concrete handling logic
}
std::string getType() const override {
return "concrete";
}
void handleSpecific() {
// Type-specific logic stays in derived class
}
};
// Fixed: Factory in separate class
class HandlerFactory {
private:
using Creator = std::function<std::unique_ptr<FixedBaseHandler>()>;
std::map<std::string, Creator> creators;
public:
void registerHandler(const std::string& type, Creator creator) {
creators[type] = std::move(creator);
}
std::unique_ptr<FixedBaseHandler> create(const std::string& type) {
auto it = creators.find(type);
if (it == creators.end()) {
return nullptr;
}
return it->second();
}
};
// Usage
int main() {
HandlerFactory factory;
factory.registerHandler("concrete", []() {
return std::make_unique<FixedConcreteHandler>();
});
auto handler = factory.create("concrete");
if (handler) {
handler->handle();
}
return 0;
}
CVE Examples
This CWE is marked as PROHIBITED for direct CVE mapping as it represents a code quality/design concern rather than a direct security vulnerability.
Related CWEs
- CWE-710: Improper Adherence to Coding Standards (parent)
- CWE-1047: Circular Dependency (related)
- CWE-1055: Multiple Inheritance from Concrete Classes (related)
- CWE-1227: Encapsulation Issues (category member)
References
- MITRE Corporation. "CWE-1062: Parent Class with References to Child Class." https://cwe.mitre.org/data/definitions/1062.html
- Martin, Robert C. "Clean Architecture: A Craftsman's Guide to Software Structure and Design."
- Gamma, Erich et al. "Design Patterns: Elements of Reusable Object-Oriented Software."