Loading...
Hristo_Penchev avatar Hristo_Penchev 389 Точки

[Homework] OOP - Inheritance and Abstraction - Problem {1} - School - викане на конструктор от базов клас

Здравейте,

Явно правя някаква много елементарна грешка, но не мога да я открия. Ето конструктира на абстрактния базов клас Person:

  1. public Person(string name, string details = null)
  2.     {
  3.         this.Name = name;
  4.         this.Details = details;
  5.     }

Тук го викам в конструктора на класа наследник Student:

public Student(uint number) : base(name, details)
{
this.UniqueClassNumber = number;
}

 

Компилаторът пищи, че не може да ги достъпи поради ниво на достъп. Не мога да разбера какво иска - ние не достъпваме private полета, а конструктор. Така съм го правил и при други класове с онаследяване. Ето линк към целия код:
http://pastebin.com/cX9FVakJ

http://pastebin.com/jvBBJfZG

http://pastebin.com/Hjfm2tBE

http://pastebin.com/mfWiAaAv

Благодаря предварително!

Тагове:
0
C# OOP Basics
a.angelov avatar a.angelov 1316 Точки

Мисля, проблема ти идва от това, че не слагаш и другите необходими параметри в конструктура на Student:

public Student(string name, string details = null, uint number) : base(name, details)

4
Hristo_Penchev avatar Hristo_Penchev 389 Точки

Стана. Значи всъщност то копира във втората част на конструктора след base информацията от първата част

0
a.angelov avatar a.angelov 1316 Точки

Александър също е прав за нивата на достъп на класовете. Уточнявай ги изрично за да не се объркваш /при теб класовете са с достъп по подразбиране internal/.

1
AleksandurSeferinkin avatar AleksandurSeferinkin 333 Точки

Такива проблеми се получават когато двата класа са с различно ниво на достъп. Примерно интерфейсите са ти публични, а класовете internal. Хубаво е всички неща в c# да си имат изрично зададено ниво на достъп, за да виждаш разликите. Всичко си има default-но такова, примерно класовете, интерфейсите, структурите и енумерациите са internal, а полетата в класовете/структурите са private. Погледни си абстрактния клас Person, конструктора му и някъде ще има разминаване.

 

ПС: На две места извикваш base конструктора с подадени аргументи, но тези не са дефинирани никъде.

public Student() : base(name, details) { }

Тук това name и details от къде идва? 

1
24/01/2015 18:53:44
Hristo_Penchev avatar Hristo_Penchev 389 Точки

Благодаря ти за отговора и за насоката с нивата на достъп. Обаче нещо се прецаква там: Имам следния код за класа Discipline:
http://pastebin.com/JMH96826

дава ми следната грешка:

Error 1 Inconsistent accessibility: property type 'System.Collections.Generic.IList<Student>' is less accessible than property 'Discipline.Students' C:\Users\Ico\Documents\Visual Studio 2013\Projects\InheritanceAndAbstraction\Problem01_School\Disciplines.cs 35 27 Problem01_School

Като махна Public пред класа и се оправя, но не разбирам защо се получава така.

П.С. Виждам, че вече и въпрос да зададе човек - следва истеричен хейт и минуси на поразия. Не че знам за какво са тези форумни точки де, но все си мислех, че форумите са за обмен на информация. Но който се чувства щастлив да бие минуси - да заповяда :)

3
AleksandurSeferinkin avatar AleksandurSeferinkin 333 Точки

Класа Student public ли е?

Ако един клас е публичен, всички пропъртита и методи, които също са публични, трябва да връщат публичен тип.  Идеята е там, че ако някой отвън/друго асембли/ реши да ползва този клас и ти му връщаш internal/private тип, той няма как да го ползва, защото за него никъде няма да е дефиниран. Visual Studio това го вижда и ти казва, че правиш простотия.

"property type 'System.Collections.Generic.IList<Student>' is less accessible than property 'Discipline.Students'" - Типа IList<Student> е по-малко достъпен от пропъртито Students. IList си идва от .NET и си е публичен, но класа Student май си е internal.

1
27/01/2015 00:12:18
AleksandurSeferinkin avatar AleksandurSeferinkin 333 Точки

Всички полета в класа ти са дефинирани без зададено ниво на достъп - това, което ще ти създава проблеми.

В C# много лесно можеш да запомниш кое се нуждае от private/public/protected/internal и кое не. Само променливите в body-то на методите и пропъртитата не им трябва такова - те се намират в scope и е безсмислено. Всичко останало е дори задължително да му посочиш нивото на достъп.

Също така вместо да правиш пропъртита без никакви проверки, можеш да се възползваш от автоматичните такива.

public int PropName { get; set; } - Това създава и `скрито` private поле, което ще те подсигури, че спазваш ООП `законите`. Спестяваш си писане + сума редове код.

Променен код.

И още нещо... Винаги инициализирай всяка една променлива още в момента, в който я декларираш!

1
XmUrF avatar XmUrF 363 Точки

Александър е прав. Ти не си дал класа Person да видим как си го направил, но в случая класът Student не е пъблик. Направи ги да са еднакви.

0
a.angelov avatar a.angelov 1316 Точки

Щом му се е получило с моето предположение, значи и класа Person вероятно е без модификатор за достъп - тоест е internal, като този на Student.

1
24/01/2015 19:02:07
XmUrF avatar XmUrF 363 Точки

Oчевидно :). Но с него сме писали практически по едно и също време и не съм видял отговора му. Иначе предположих, че става въпрос за достъпа тъй като и самият той казва, че компилаторът му пищи с такава грешка.

0
a.angelov avatar a.angelov 1316 Точки

Аз в интерес на истината не бях стигнал до това каква грешка точно му дава - само погледнах конструктурите... :)

0
mihayloff14 avatar mihayloff14 824 Точки

Във връзка със същата задача искам да попитам следното:

Тъй като по условие се изисква всеки ученик да има unique class number, според мен би трябвало това да се определя спрямо класа, в който участва, а не да служи просто като уникално ID с което да се различава от всички други ученици.

Например:

Ученик Михаела може да има номер в класа 10 и да участва в клас 10б, а ученик Милен също номер 10, но да участва в клас 11а. Повечето решения на тази задача, която видях просто дефинират едно статично поле, което разпределя уникални номера на различните ученици, независимо от класовете им.

Възможно ли е да се направи поле, което да може да се променя единствено от класа Class, когато ученикът зачленува в него и освен това, да може да се енкапсулира от външния свят. Тъй като лесно решение би било да направим публично property, което да се променя в момента, в който ученикът зачленува в клас, но то също ще бъде достъпно и от всички останали класове.

 

0
24/01/2015 22:35:51
RoYaL avatar RoYaL Trainer 6849 Точки

Възможно е, но не е правилно според мен. Така couple-ваш два класа.

Не се ли целиш в нещо подобно?: ЛИНК

Аксесорът на UniqueNumber връща конкатенирания стринг от класа, буквата и номерът в клас. Така ако няма дублиращи се номера в клас, няма да има и дублиращи се уникални в един клас. Но също така няма проблем номер 16 да съществува в 10ти Б клас. Тогава UniqueNumber ще върне 10b16.

От друга страна пропъртито няма мутатор (setter) съответно няма как някой от външния свят да го промени от 10b16 на 11a16. Възможността е някой да смени класа от 10ти Б на 11ти А, но тук може да се намеси проверка дали вече няма такъв номер в този клас.

Не съм разгледал условието на задачата, но ми се струва и неправилно да може някой да смени класа на студента. Като цяло даже не е правилно да може да се сменя информацията на един обект от тип клас, т.е. там полетата трябва да са рийдонли.

Ако един ученик трябва да смени класа си, и ако следваме здравия разум - един ученик не може да влезе в по-долен клас, то единственият вариант е да повиши класа си или да смени паралелката. Тогава трябва да има два експоузвани метода - Move(Class newClass) и Graduate().

В реална ситуация, ако по време на учебната година по някакви неведоми обстоятелства някой сени паралелката си, става последен номер в класа, независимо от името му. Така, че Move() трябва да вземе предвид новоподадения клас, първо да провери дали не е по-ниска или висока цифра, защото трябва да позолим само смяна на паралелката, тъй като не може да мутираме буквата на вече съществуващ клас, трябва да подадем изцяло нов обект. Ако всичко е точно и буквата е различна от сегашната - просто намира сет-а от студенти в новия клас и съответно техният брой и променя номерът на ученика на максимума + 1. Така логиката за UniqueNumber няма да се счупи и отново ще имаме уникален.

При Graduate() трябва отново да се създаде нов обект, този път проверяваме дали цифрата е по-голяма и ако е - тогава правим разпределяме ученика по азбучен ред и му слагаме номер. Та, сигурно много се отплеснах от условието на задачата, но отговорът ми е насочен към това за правилния начин да се направи уникален идетнификатор спрямо класа и буквата, и външния свят да не може да го счупи това.

-1
25/01/2015 12:29:53
mihayloff14 avatar mihayloff14 824 Точки

Да, мисля че наистина така може да стане, но по условие на задачата Class-а би трябвало да има ученици, а не обратното.

Освен това, и в реалния свят мисля, че няма как един ученик да има свой клас.

Въпреки че може би вече навлизаме в подробности и в крайна сметка няма да правя нови промени по кода, но все пак ми е интересно как би могло да се измисли нещо от сорта.

0
25/01/2015 09:09:00
RoYaL avatar RoYaL Trainer 6849 Точки

Ми ще стане с доста огромни хакове итерирайки през обектите от тип Клас, намирайки ученика и правейки нещо с него.

Да, учениците си нямат собствен клас, но знаят за него. Нещата, които не трябва да имаш като полета, са нещата, които пряко не е нужно да знаеш за тях. Но е hardly believable, че ученик може да съществува без училище или клас.

Ако все пак смяташ, че ученик може да съществува без училище или клас и искаш да decouple-неш ученикът от класа, т.е. дори и да преместиш класът Ученик в друг проект, където не същстевува клас Клас, пак да работи системата, тогава трябва да си направиш някаква отделна структура, например междинен клас, който да държи key => value pair Class => Student.

Така лесно можеш да влезеш в този клас, да кажеш на определен ученик Graduate() той да го премести в тази структура от данни и да го премести и в Листа от ученици, който Class държи.

А това за което питаше в по-горния пост е това:

        public void Gradute()
    {
        var callerClass = new StackFrame (1).GetMethod ().DeclaringType;
        if (callerClass != typeof(Class)) 
        {
            throw new Exception ("Cannot call this method from outside object of type Class");
        }
    }

 

2
a.polyanska avatar a.polyanska 107 Точки

Здравейте,

Имам подобен проблем, като колегата, но със задачата Animals. Затова и задавам въпроса тук, а не отварям нова тема. Прочетох отговорите, но въпреки всичко съм объркана и не мога да разбера откъде идва проблемът ми. В задачата съм задала някакви конструктори и пропъртита за име, възраст и пол на базовия клас Animal. Достъпът до тях е публичен. Ето кода: Animal

Когато, обаче, се опитам да дам на класа Dog, който наследява Animal да преизползва конструктора от базовия клас:

 public Dog(string dogName, decimal dogAge, Gender dogGender)
            : base(Name, Age, gender)

 

не ми приема нито Name, нито Age, нито gender-a, a ми дава грешка "Object reference is required".

Още повече ме обърква фактът, че СЪВСЕМ същото нещо (или поне си мисля, че е същото :) ) направих и в предната задача и сработи без никакъв проблем. Някой може ли да ми даде насока къде бъркам?

Благодаря!

0
30/01/2015 20:09:49
Filkolev avatar Filkolev 4482 Точки

Когато викаш базовия конструктор просто му подай параметрите, които са подадени на конструктора на кучето, т.е.:

: base(dogName, dogAge, doggender)

1
a.polyanska avatar a.polyanska 107 Точки

Ха, явно съвсем съм се оплела и крайно грешно съм схванала цялата концепция! Аз мислех, че трябва да извикаме параметрите с имената от базовия клас. Много ме помешаха тези еднакви имена, малки и големи букви и т.н. Както и да е- така, разбира се, сработи и по-важното- просветна ми поредното погрешно разбиране на нещата :) Много ти благодаря, полезен играч, както винаги :)

1
RoYaL avatar RoYaL Trainer 6849 Точки

Не ги викаш (те не съществуват), а ги подаваш (искаш да им пратиш някакви стойности)

1
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.