#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;
};