VotingClassifier Doesn't work when use CatboostClassifier among estimators

### Describe the bug

VotingClassifier Doesn't work when using CatboostClassifier among estimators

### Steps/Code to Reproduce

here is my test case

```python
from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import RandomForestClassifier
from catboost import CatBoostClassifier
from lightgbm import LGBMClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# Generating sample data with adjusted parameters
X, y = make_classification(n_samples=1000, n_features=20, n_classes=3,
                           n_clusters_per_class=1, n_informative=2,
                           random_state=42)

# Splitting the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Creating base classifiers
rf_clf = RandomForestClassifier(random_state=42)
catboost_clf = CatBoostClassifier(random_state=42, verbose=False)
lgbm_clf = LGBMClassifier(random_state=42)

# Creating the voting classifier
voting_clf = VotingClassifier(
    estimators=[('rf', rf_clf), ('catboost', catboost_clf), ('lgbm', lgbm_clf)],
    voting='hard'  # Change to 'soft' for soft voting
)

# Training the voting classifier
voting_clf.fit(X_train, y_train)

# Making predictions
y_pred = voting_clf.predict(X_test)

# Evaluating the performance
accuracy = accuracy_score(y_test, y_pred)
accuracy_percentage = accuracy * 100
print("Accuracy: {:.2f}%".format(accuracy_percentage))
```

### Expected Results
prediction and accuracy of classifier


If I replace CatBoost by other classifier, it works perfectly
can you help please?

### Actual Results
```python
Traceback (most recent call last)
Cell In[68], line 32
     29 voting_clf.fit(X_train, y_train)
     31 # Making predictions
---> 32 y_pred = voting_clf.predict(X_test)
     34 # Evaluating the performance
     35 accuracy = accuracy_score(y_test, y_pred)

File ~/anaconda3/lib/python3.11/site-packages/sklearn/ensemble/_voting.py:369, in VotingClassifier.predict(self, X)
    366     maj = np.argmax(self.predict_proba(X), axis=1)
    368 else:  # 'hard' voting
--> 369     predictions = self._predict(X)
    370     maj = np.apply_along_axis(
    371         lambda x: np.argmax(np.bincount(x, weights=self._weights_not_none)),
    372         axis=1,
    373         arr=predictions,
    374     )
    376 maj = self.le_.inverse_transform(maj)

File ~/anaconda3/lib/python3.11/site-packages/sklearn/ensemble/_voting.py:68, in _BaseVoting._predict(self, X)
     66 def _predict(self, X):
     67     """Collect results from clf.predict calls."""
---> 68     return np.asarray([est.predict(X) for est in self.estimators_]).T

ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 2 dimensions. The detected shape was (3, 200) + inhomogeneous part.```

### Versions

```shell
System:
    python: 3.11.5 (main, Sep 11 2023, 13:54:46) [GCC 11.2.0]
executable: /home/karim/anaconda3/bin/python
   machine: Linux-5.15.0-105-generic-x86_64-with-glibc2.31

Python dependencies:
      sklearn: 1.3.0
          pip: 23.2.1
   setuptools: 68.0.0
        numpy: 1.24.3
        scipy: 1.11.1
       Cython: None
       pandas: 2.0.3
   matplotlib: 3.7.2
       joblib: 1.2.0
threadpoolctl: 2.2.0

Built with OpenMP: True

threadpoolctl info:
       filepath: /home/karim/anaconda3/lib/libmkl_rt.so.2
         prefix: libmkl_rt
       user_api: blas
   internal_api: mkl
        version: 2023.1-Product
    num_threads: 4
threading_layer: intel

       filepath: /home/karim/anaconda3/lib/libiomp5.so
         prefix: libiomp
       user_api: openmp
   internal_api: openmp
        version: None
    num_threads: 8

       filepath: /home/karim/anaconda3/lib/libgomp.so.1.0.0
         prefix: libgomp
       user_api: openmp
   internal_api: openmp
        version: None
    num_threads: 8

       filepath: /home/karim/anaconda3/lib/python3.11/site-packages/xgboost.libs/libgomp-a34b3233.so.1.0.0
         prefix: libgomp
       user_api: openmp
   internal_api: openmp
        version: None
    num_threads: 8
```

COMMENT:
> Closing this, but also cc @glemaitre who might think we should convert (n_samples, 1) to (n_samples,)

I would advocate that `predict` contract should be `(n_samples,)` or `(n_samples, n_outputs)`. Our estimator check should check for those shape (`check_classifiers_train`).

Labels: Bug, Needs Triage