Implement a binary search tree in C++ with functions to insert, delete, and search for nodes. The program should also include an inorder traversal function that prints the sorted values of the tree.

```cpp
#include <iostream>

class Node {
public:
    int data;
    Node* left;
    Node* right;

    Node(int d) : data(d), left(nullptr), right(nullptr) {}
};

class BinarySearchTree {
public:
    Node* root;

    BinarySearchTree() : root(nullptr) {}

    void insert(int value) {
        if (root == nullptr) {
            root = new Node(value);
        } else {
            insertHelper(root, value);
        }
    }

    bool search(int value) {
        return searchHelper(root, value);
    }

    void remove(int value) {
        root = removeHelper(root, value);
    }

    void inorderTraversal() {
        inorderTraversalHelper(root);
        std::cout << std::endl;
    }

private:
    void insertHelper(Node* node, int value) {
        if (value < node->data) {
            if (node->left == nullptr) {
                node->left = new Node(value);
            } else {
                insertHelper(node->left, value);
            }
        } else {
            if (node->right == nullptr) {
                node->right = new Node(value);
            } else {
                insertHelper(node->right, value);
            }
        }
    }

    bool searchHelper(Node* node, int value) {
        if (node == nullptr) {
            return false;
        } else if (node->data == value) {
            return true;
        } else if (value < node->data) {
            return searchHelper(node->left, value);
        } else {
            return searchHelper(node->right, value);
        }
    }

    Node* removeHelper(Node* node, int value) {
        if (node == nullptr) {
            return node;
        }

        if (value < node->data) {
            node->left = removeHelper(node->left, value);
        } else if (value > node->data) {
            node->right = removeHelper(node->right, value);
        } else {
            if (node->left == nullptr) {
                Node* temp = node->right;
                delete node;
                return temp;
            } else if (node->right == nullptr) {
                Node* temp = node->left;
                delete node;
                return temp;
            }

            node->data = minValue(node->right);

            node->right = removeHelper(node->right, node->data);
        }
        return node;
    }

    int minValue(Node* node) {
        int minv = node->data;
        while (node->left != nullptr) {
            minv = node->left->data;
            node = node->left;
        }
        return minv;
    }

    void inorderTraversalHelper(Node* node) {
        if (node != nullptr) {
            inorderTraversalHelper(node->left);
            std::cout << node->data << " ";
            inorderTraversalHelper(node->right);
        }
    }
};

int main() {
    BinarySearchTree bst;

    bst.insert(50);
    bst.insert(30);
    bst.insert(20);
    bst.insert(40);
    bst.insert(70);
    bst.insert(60);
    bst.insert(80);

    bst.inorderTraversal(); // 20 30 40 50 60 70 80

    std::cout << "Search 40: " << (bst.search(40) ? "Found" : "Not Found") << std::endl; // Found
    std::cout << "Search 90: " << (bst.search(90) ? "Found" : "Not Found") << std::endl; // Not Found

    bst.remove(20);
    bst.remove(30);
    bst.remove(50);

    bst.inorderTraversal(); // 40 60 70 80

    return 0;
}
```