Создайте класс, который содержит все функции его родительского класса, кроме одной

#c #c 11 #inheritance #visual-c

#c #c 11 #наследование #visual-c

Вопрос:

Предположим, у меня есть два класса, один из которых:

 class A{
public:
    void f1()
    {
        cout << "function 1";
    }
    void f2()
    {
        cout << "function 2";
    }
    void f3()
    {
        cout << "function 3";
    }
};
 

Теперь я хочу, чтобы класс B содержал все функции A except f3 .

то, что я делаю, это:

 class B: public A
{
    private:
    void f3()
    {

    }
};
 

Насколько мне известно, B::f3() скрывается определение A::f3() , и, поскольку B::f3() оно является закрытым, f3() оно недоступно через класс B . Но что я все еще могу сделать, так это назвать это так:

 B var();
var.A::f3();
 

Есть ли какой-нибудь способ, которым я мог бы полностью скрыться f3 от класса B , используя наследование и не меняя класс A ?

Комментарии:

1. Наследование полезно расширять, а не ограничивать. Возможно, вы захотите вместо этого использовать композицию в вашем случае.

2. Если дочерний класс не обладает всей функциональностью своего родительского класса, то он, вероятно, не должен быть производным от него.

Ответ №1:

Не приобретайте привычку объединять классы по частям посредством наследования, смешивая и сопоставляя классы, которые делают примерно то, что вы хотите. Это приводит к ужасному коду.

Однако иногда имеет смысл реализовать один класс с помощью другого. В тех случаях, если вы используете наследование, «правильный» способ сделать это — использовать частное наследование.

И под «правильным» я подразумеваю наиболее приемлемый способ.

 class A
{
public:
    void f1()
    {
        cout << "function 1";
    }
    void f2()
    {
        cout << "function 2";
    }
    void f3()
    {
        cout << "function 3";
    }
};

class B: private A
{
public:
    using A::A; // use A's constructors
    using A::f1;
    using A::f2;
    // do not use f3
};
 

Времена, когда это может иметь смысл, — это когда композиция слишком утомительна из-за большого количества задействованных методов.

Комментарии:

1. Частное наследование можно рассматривать как означающее «реализованное в терминах». Т.е. «класс B реализован в терминах класса A». Это именно та проблема, для решения которой предназначено частное наследование.

Ответ №2:

Вы не B должны наследовать от A .

Если B не хватает какой-либо функциональности A , то B и A не имеют отношения is-a, которое наследование предназначено для моделирования (и которого ожидают клиенты). Вместо этого вы должны использовать композицию: введите член B типа A of .

Комментарии:

1. Или разделите класс A на несколько классов. Один класс, из которого B может быть полностью производным. Зависит от вашей ситуации. По крайней мере, это признак того, что ваш дизайн класса нуждается в дополнительной работе.

2. Если я создаю A в классе B, то мне, вероятно, придется писать функции-оболочки для каждой требуемой функции A, что может быть довольно раздражающим в случае примеров из реальной жизни.

3. @SaifUllah Тогда, возможно, вам следует выяснить, может ли предложение Respect2All сработать для вас.

4. @SaifUllah Взвесьте это: гораздо более досадно найти такую кодовую базу позже и понять, что ее первоначальный автор ненадлежащим образом использовал наследование повсюду, просто чтобы сэкономить время ввода, как кто-то, кому теперь приходится убирать все ненужные накладные расходы на связь и vtable (размер и время), которые привела лень упомянутого автора. Кстати, и «первоначальный автор», и «кто-то» могут быть одним и тем же человеком; не стоит недооценивать свою способность раздражать себя в будущем. Я говорю по опыту как человек, который на собственном горьком опыте убедился, что наследование спама создает реальные накладные расходы и проблемы при попытке последующего рефакторинга

Ответ №3:

Вы можете мошенничать с частным наследованием

 class B : private A
{
public:
    using A::f1;
    using A::f2;
};