» »

[C++] Dedovanje, virtualne in abstraktne metode

[C++] Dedovanje, virtualne in abstraktne metode

black ice ::

OOP mi kar naprej povzroča težave.

Kakšna je razlika med virtualno in abstraktno metodo?
Če si pravilno razlagam se virtualna metoda izvede le na koncu hierarhije (v izpeljanih razredih), če je tam ni se izvede tista v baznem razredu. Abstraktna metoda potemtakem nima implementacije v baznem razredu ampak samo v izpeljanih. Je pri obeh obvezno določilo virtual? Sprašujem zato, ker sem na netu zasledil primere v Javi, kjer je določilo abstract, pri C++ mi pa Eclipse javi napako, ko uporabim to določilo.

Spodaj imam en primer, ki ga skušam rešiti. Imam bazni oz. starševski razred Prenocisce iz katerega hočem (javno) izpeljati razreda HotelskaSoba in Apartma. Pri izpeljavi razreda HotelskaSoba ni nobenih težav, v razredu Apartma mi javi sledečo napako:
..\src\/Apartma.h:13:35: error: expected class-name before '{' token

Še koda:
#ifndef PRENOCISCE_H_
#define PRENOCISCE_H_
#include <string>

namespace std {

class Prenocisce {
protected:
	string oznaka;
public:
	Prenocisce();
	virtual ~Prenocisce();
	virtual void izpis();
	virtual int vrni_ceno();
};

} /* namespace std */
#endif /* PRENOCISCE_H_ */

#ifndef HOTELSKASOBA_H_
#define HOTELSKASOBA_H_

namespace std {

class HotelskaSoba : public Prenocisce {
protected:
	int st_oseb;
	int cena_na_osebo;

public:
	HotelskaSoba();
	virtual ~HotelskaSoba();

};

} /* namespace std */
#endif /* HOTELSKASOBA_H_ */

#ifndef APARTMA_H_
#define APARTMA_H_

namespace std {

class Apartma : public Prenocisce {
protected:
	int cena;

public:
	Apartma();
	virtual ~Apartma();
};

} /* namespace std */
#endif /* APARTMA_H_ */

Something ::

V javi pred imenom razreda napišeš, da je razred abstrakten z rezervirano besedo abstract, v c++ pa tega ni. Razred je avtomatsko abstrakten, če vsebuje eno abstraktno metodo in to je taka, kjer samo napišeš = 0.
In ja pri abstraktni metodi je potrebtno tudi zapisat virtual.
Virtualna metoda pa pomeni, da če imaš kazalec, ki je tipa nadrazreda, kaže pa na kak njegov izpeljan razred, se bo klicala metoda izpeljanega razreda. Če pa metoda ni virtualna pa se bo vedno klicala metoda nadrazreda.
Pa v teh podrazredih moraš includat header od nadrazreda. Mislim, da ti zato javlja napako.

Mesar ::

Virtualen destruktor? Zakaj pa je to dobro?
Your turn to burn!

Something ::

Ker če destruktor ni virtualen, se lahko zgodi, da boš izbrisal samo tisti del razreda, ki je dedovan in ne celotnega.

Mesar ::

Oh I see now... http://www.gotw.ca/publications/mill18....

Avtorju... a maš #include "Prenocisce.h" ? Oz. ime .h fila v katerem je razred Prenocisce...
Your turn to burn!

Vesoljc ::

black ice je izjavil:

Kakšna je razlika med virtualno in abstraktno metodo?


virtual = you can
abstract = you must
Abnormal behavior of abnormal brain makes me normal...

Vesoljc ::

class base {
public:
   virtual void foo1() { int dummy; }     // virtual, you can override
   virtual void foo2() = 0;               // pure virtual, abstract, you must implement
};

class a : public base {
public:
   void foo1() { base::foo1(); int mydummy; }   // override and call base
   void foo2() { int mynew; }                   // just implement
};

class b : public base {
public:
   void foo1() { int nobase; }            // implement, no base call
   void foo2() { int mynew; }             // just implement
};
Abnormal behavior of abnormal brain makes me normal...

mallard ::

Pa še:
#include <iostream>

struct base {
    virtual void foo() = 0;  // abstraktna metoda
};

void base::foo()  // ampak ima lahko implementacijo
{
    std::cout << "Hey!";
}

// base b;   // <-- base je kljub temu abstrakten razred, to se ne prevede

struct derived : base {
    virtual void foo() { base::foo(); }  // kličemo implementacijo iz nadrazreda
};

int main()
{
    derived d;
    d.foo(); // Hey!
}

black ice ::

Hvala za primere, mi je postalo malenkost bolj jasno.
Sem includal header izvornega razreda in se mi tista napaka več ne pojavlja, sedaj pa imam nekje semantično napako.

Description	Resource	Path	Location	Type
Symbol 'Prenocisce' could not be resolved	Apartma.h	/Vaja0601/src	line 15	Semantic Error
Symbol 'Prenocisce' could not be resolved	HotelskaSoba.h	/Vaja0601/src	line 16	Semantic Error
Symbol 'Prenocisce' could not be resolved	HotelskaSoba.h	/Vaja0601/src	line 22	Semantic Error

#ifndef PRENOCISCE_H_
#define PRENOCISCE_H_
#include <string>
#include <iostream>

namespace std {

class Prenocisce {
protected:
	string oznaka;

public:
	Prenocisce(string o) : oznaka(o) {}
	virtual ~Prenocisce() {}
	virtual void izpis() {}
	virtual int vrni_ceno() = 0;
};

} /* namespace std */
#endif /* PRENOCISCE_H_ */

#ifndef HOTELSKASOBA_H_
#define HOTELSKASOBA_H_

#include <string>
#include "Prenocisce.h"

namespace std {

class HotelskaSoba : public Prenocisce {
protected:
	int st_oseb;
	int cena_na_osebo;

public:
	HotelskaSoba (string o, int sto, int cno): Prenocisce(o), st_oseb(sto), cena_na_osebo(cno) {}
	virtual ~HotelskaSoba() {}
	void izpis() {cout << "St. oseb: " << st_oseb << " cena na osebo: " << cena_na_osebo;}
	int vrni_ceno() {return st_oseb*cena_na_osebo;}
};

} /* namespace std */
#endif /* HOTELSKASOBA_H_ */

#ifndef APARTMA_H_
#define APARTMA_H_
#include "Prenocisce.h"
#include <string>

namespace std {

class Apartma : public Prenocisce {
protected:
	int cena;

public:
	Apartma(int c): cena(c) {}
	virtual ~Apartma() {}
	void izpis() {cout << "Cena: " << cena;}
};
} /* namespace std */
#endif /* APARTMA_H_ */

Mesar ::

Datoteka ja Prenocisce.h ali prenocisce.h? Imaš dodane datoteke v projekt?
Your turn to burn!

black ice ::

Datoteka je Prenocisce.h. Vse omenjene datoteke so v istem projektu.

mallard ::

Zakaj postavljaš svoje razrede v namespace std? To samo kliče po težavah, std je rezerviran za implementacijo standardne knjižnice. V headerjih kvalificiraj imena iz standardne knjižnice, npr std::string, v cpp datotekah pa lahko rečeš "using namespace std;"

Mesar ::

To se je meni čudno zdelo tudi. Keri prfox je že tak pisal uso kodo?
Your turn to burn!

mallard ::

Pa v razredu Apartma moraš tudi implementirat abstraktno metodo vrni_ceno() iz prenočišča.

glede namespaca std:

[C++11: 17.6.4.2.1/1]: The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.

Zgodovina sprememb…

  • spremenilo: mallard ()

black ice ::

Glede pisanja razredov v namespace std: Eclipse ima možnost, da ti sam ustvari razrede in pripadajoče konstruktorje ter destruktorje.

mallard ::

black ice je izjavil:

Glede pisanja razredov v namespace std: Eclipse ima možnost, da ti sam ustvari razrede in pripadajoče konstruktorje ter destruktorje.


Nisem prepričan, če se razumeva. Razredi so že v redu nastavljeni, ampak ne bi smeli bit definirani v namespace-u std, ampak v kakem drugem, npr. moj_nejmspejs, moj_std ali karkoli že. Če ti eclipse nastavi namespace std, potem se mu mal blede :)


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

Java program (strani: 1 2 )

Oddelek: Programiranje
507892 (7041) kunigunda
»

Pomoč pri programiranju v C++

Oddelek: Programiranje
141715 (1282) amacar
»

Iščem program c++

Oddelek: Programiranje
6806 (674) krneki0001
»

[C++] Linker error

Oddelek: Programiranje
51205 (1205) Quikee
»

[C++] Problem z dedovanjem šablon (template inhieritance)

Oddelek: Programiranje
131538 (1416) Gundolf

Več podobnih tem