Ваша ссылка неверна. Ваша референтная база данных должна указывать на fnBOM ..... вместо «GTjrWgpKjoeXUt4JdBJTYP1JkVT2»
final DatabaseReference receiver =
users.child("GTjrWgpKjoeXUt4JdBJTYP1JkVT2").child("fnBom...");
, и вы можете хранить каждый дочерний объект на арифметике, а последний элемент доступа - arraylist
myArrayList.get(myArrayList.size()-1);
Как многие из парней отметили, что это законно.
Однако, часть «IS-A» не так проста. Когда дело доходит до «динамического полиморфизма», имеет место соотношение «IS-A», I.e. все, что вы можете сделать с Super, вы также можете делать с Derived экземпляром.
Однако в C ++ у нас также есть то, что часто называют статическим полиморфизмом (шаблоны, большую часть времени). Рассмотрим следующий пример:
class A {
public:
virtual int m() {
return 1;
}
};
class B : public A {
private:
virtual int m() {
return 2;
}
};
template<typename T>
int fun(T* obj) {
return obj->m();
}
Теперь, когда вы пытаетесь использовать «динамический полиморфизм», все выглядит нормально:
A* a = new A();
B* b = new B();
// dynamic polymorphism
std::cout << a->m(); // ok
std::cout << dynamic_cast<A*>(b)->m(); // ok - B instance conforms A interface
// std::cout << b->m(); fails to compile due to overriden visibility - expected since technically does not violate IS-A relationship
... но когда вы используете " статический полиморфизм "вы можете сказать, что отношение« IS-A »больше не выполняется:
A* a = new A();
B* b = new B();
// static polymorphism
std::cout << fun(a); // ok
//std::cout << fun(b); // fails to compile - B instance does not conform A interface at compile time
Итак, в конечном итоге изменение видимости метода является« довольно законным », но это одна из уродливых вещей в C ++, что может привести к ловушке.
Да, это разрешено до тех пор, пока подпись будет одинаковой. И , на мой взгляд, , да, вы правы, переопределение видимости (например, public -> private) прерывает IS-A. Я полагаю, что у Скотта Майерса «Эффективная серия C ++» есть обсуждение этого вопроса.
Да, это законно, доступность проверяется статически (не динамически):
class A {
public:
virtual void foo() = 0;
private:
virtual void bar() = 0;
};
class B : public A {
private:
virtual void foo() {} // public in base, private in derived
public:
virtual void bar() {} // private in base, public in derived
};
void f(A& a, B& b)
{
a.foo(); // ok
b.foo(); // error: B::foo is private
a.bar(); // error: A::bar is private
b.bar(); // ok (B::bar is public, even though A::bar is private)
}
int main()
{
B b;
f(b, b);
}
Теперь, зачем вы хотите это сделать? Это имеет значение только при непосредственном использовании производного класса B
(второй параметр f()
), а не через базовый интерфейс A
(первый параметр f()
). Если вы всегда используете абстрактный A
интерфейс (как я бы рекомендовал в целом), он по-прежнему соответствует режиму «IS-A».
Разрешено в обоих направлениях (т. е. от private
до public
И от public
до private
).
С другой стороны, я бы сказал, что это не нарушить связь IS-A. Я основываю свой аргумент на двух фактах:
Base&
(или Base*
), у вас есть точно такой же интерфейс, что и до public
и вызов метода private
напрямую в любом случае: тот же эффект с большим количеством ввода