Java-программист - как люди на C ++ используют классы? Указатели на классы, параметры по умолчанию? - PullRequest
7 голосов
/ 19 февраля 2009

Я знаю свой подход к объектно-ориентированному программированию, но я привык к Java, и я никогда не трогал C ++ до недавнего времени.

Я думаю, что моя проблема не столько связана с синтаксисом, сколько с философией ООП в С ++. Я понимаю разницу между указателями и адресами и стек, куча и прочее, но я все еще чувствую, что что-то упустил.

Вот пример: у меня есть класс (Shape), который содержит некоторые данные. у меня есть другой класс (приложение), используя несколько форм.

class Square {
    private: 
        int x;
        int y;
        int size;

    public:
        /* constructor */
        Square(int x, int y, int size);
}


class App {
    private:
        Square redSquare;
        Square blueSquare;

    public:
        void setup();
        void draw();
}

В какой-то момент что-то собирается создать экземпляр моего приложения и вызвать setup (). Проблема в том, что когда я объявляю класс App (скажем, в App.hpp), создаются экземпляры «redSquare» и «blueSquare», а не просто объявляются. Будучи программистом на Java, я бы в этом примере создал свои классы в setup (). Но это значит, что я не могу сделать это, как указано выше, мне нужно настроить redSquare и blueSquare как POINTERS, а затем я могу создать их, используя new в setup ().

Но так ли это? Или вы бы сделали конструктор по умолчанию параметры, создайте redSquare и blueSquare, как указано выше, а затем установите значения этих квадратов в App.setup (), используя что-то вроде Square.init (x, y, размер) или что-то? Или как-то иначе?

Вы когда-нибудь объединяли классы или только указатели?

Я, конечно, могу взломать это так или иначе, так что оно работает само, но у меня есть ощущение, что я делаю вещи "по-Java" и не понимаю, как думают программисты на C ++.

Ответы [ 12 ]

0 голосов
/ 19 февраля 2009

Я позволю коду говорить. Предупреждение: непроверенный код!

/**
    Typically we will use Shape as a base class.
    This defines the interface that clients of the
    Shape class can expect and use reliably. Of
    course, some shapes can be dough-nuts and have 
    a eat() method, but that's just them dough-nuts.
*/
class Shape
{
public:
    /**
        The base class's default ctor.
        The compiler generates one if you don't specify any ctors,
        but if you specify at least one, this is skipped, so we 
        to mention it explicitly
    */
    Shape(void) {} 
    Shape(const std::string& c) { std::cout << c.length() << std::endl; } /* print the color */
    ~Shape(void) {}

    /**
        The interface. The '=0' makes it virtual. This class
        has now become abstract. Subclasses MUST define this
        member function.
    */
    virtual size_t area() = 0 { return 0; }
};

/**
    The more interesting objects, real world shapes.
    They have their own version of implementing an
    algorithm to find out area.
*/
class Circle : public Shape
{
public:
    Circle(const std::string& color) /* no default parameters */
         /* the base class's default ctor is called automagically */
        :_color(color) /* the user must specify the color */        
    {}
    ~Circle(void) {}

    virtual size_t area() /* = 0 */ /*we dont want this to be abstract! */
            { return 42; }

private:
    std::string _color;
};

class Triangle: public Shape
{
public:
    Triangle(const std::string& color = "red") 
        Shape(color)/* this base class ctor has to be called by you */
        : _color(color) /* use initializer lists to populate ctor parameters */
    {}
    ~Triangle(void) {}

    virtual size_t area() { return 42 + sizeof Triangle; }
private:
    std::string _color;
};

/**
    We will also use design patterns. And an oft-abused 
    one -- the Singleton. We want only one app to run after
    all.
*/
class App {
public:
    /**
        This would typically be in a differnt '.cpp' file.
    */
    int Run() {
        /* create a few shapes */
        Triangle t1;
        Circle c1; // error -- no default parameter
        Circle c2("green");

        /* You want to sum the areas of all these objects */
        size_t total_area = t1.area() + c2.area();

        /* Now, how do you process different shapes in one go? */
        /* Put them in a container for base class pointers */
        std::list<Shape *> shape_list;
        shape_list.insert(&t1); 
        shape_list.insert(&c2);

        /* process them -- calculate total area differently */
        size_t total_area2 = 0;
        std::list<Shape *>::iterator f = shape_list.end();
        for (std::list<Shape *>::iterator i = shape_list.begin();
            i != f;
            ++i) {
            total_area2 += i->area(); 
            /* see why we need virtual functions? */
        }

        /* or use the STL to the hilt and do */
        size_t total_area3 = std::accumulate(shape_list.begin(), shape_list.end(), 
            0, 
            std::bind2nd(std::plus<size_t>(std::mem_fun(&Shape::area))));


    }
private:
    App();
    App(const App&);
    App& operator(const App&);
};

/* the program entry-point, you have to have one, and only one */
int main() {
    App.Run();
}
0 голосов
/ 19 февраля 2009

Либо используйте указатели, либо заставьте конструктор приложения принимать параметры, как указано выше.

(in App.h)
Square* redSquare;
Square* blueSquare;
void setup(int,int,int,int);
...

(in App.cpp)
void App::setup(int x1,int y1,int x2,int y2){
    redSquare=new Square(x1,y1);
    blueSquare=new Square(x2,y2);   // don't forget to "delete" these later
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...