Программист Java - как люди C++ используют классы? Указатели на классы, параметры по умолчанию?

Условный оператор:

pointer = (p1 != nullptr) ? p1 : p2;

Чтобы возвратить ноль, если оба не равны нулю:

pointer = (p1 && p2) ? nullptr : ((p1 != nullptr) ? p1 : p2);

Если оба равны нулю, возвращение любого из них вернет ноль.

7
задан Frederick The Fool 19 February 2009 в 10:43
поделиться

12 ответов

Необходимо указать параметры конструктору в конструкторе Приложения, например.

App(int bx, int by, bsize, int rx, int ry, int rsize) : 
blueSquare(bx, by, bsize), redSquare(rx, ry, rsize) {}

Это - просто пример, Вы будете, вероятно, использовать лучший дизайн IRL.

2
ответ дан 6 December 2019 в 12:55
поделиться

Мне кажется, что проблема возникает из присутствия "установки ()" метод. IIUC, намерение состоит в том, чтобы использовать Приложение как:

App a;
a.setup();

В каком состояние является "a" перед вызовом установка ()? То, что должно произойти, если тянут () называют на нем? Если ответ, что-то как "установка () нужно назвать перед чем-либо, что maningful мог быть сделан с объектом Приложения", затем это означает, что установка () является "настоящим" конструктором Приложения, и что текущий ctor Приложения бессмыслен. Заключение: Удалите "установку ()" метод и замените его значимым ctor.

6
ответ дан 6 December 2019 в 12:55
поделиться

Во-первых, необходимо выбрать, как Вы хотите, чтобы Ваш класс Приложения вел себя, если тянут (), назван перед установкой ():

  1. Если Вы хотите иметь некоторые предопределенные квадраты по умолчанию, то инициализируйте их в списке Инициализации приложения.

  2. Если Вы не хотите, чтобы это когда-либо произошло, то используйте указатели и защитите от этого.

Некоторые примечания по 2:

  • У Вас нет сборщика "мусора" в C/C++, необходимо 'удалить' что Вы 'новый'
  • Можно использовать "интеллектуальные указатели", чтобы иметь RAII (Распределение ресурсов Является Инициализацией), который сделает управление памятью более простым
  • Необходимо, вероятно, использовать Пустой Шаблон разработки для ухода от многих 'если (redSquare == ПУСТОЙ УКАЗАТЕЛЬ)' блоки.
  • В любом случае инициализируйте указатели в списке инициализации Приложения, или к ПУСТОМУ УКАЗАТЕЛЮ или к пустому квадратному объекту.
2
ответ дан 6 December 2019 в 12:55
поделиться

Квадратный класс имеет конструктора, который берет 3 аргумента. Класс Приложения не определяет конструктора - который подразумевает, что компилятор предоставит конструктора по умолчанию (конструктор, который не берет параметра). В конструкторе по умолчанию класса все членские переменные инициализируются конструктором по умолчанию. Так как Ваш Квадратный класс не имеет конструктора по умолчанию, Ваш код не скомпилирует.

Конструктор должен инициализировать экземпляр класса со значениями по умолчанию к его членским переменным. Если необходимо заменить какую-либо из этих переменных, то можно определить некоторый метод считывания и методы set:

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

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

        int getX() const {return x;}
        int getY() const {return y;}
        int getSize() const {return size;}

        void setX(int nx) {x = nx;}
        void setY(int ny) {y = ny;}
        void setSize(int s) {size = s;}
}

Затем вызовите эти функции для замены внутренних переменных Квадрата.

1
ответ дан 6 December 2019 в 12:55
поделиться

Дайте приложению конструктора:

App :: App() 
    : redSquare( 10, 20, 100 ), blueSquare( 50, 500, 25 ) {
}
2
ответ дан 6 December 2019 в 12:55
поделиться

Я использовал бы Квадрат * вместо Квадрата как члены парламента, не занимающие официального поста Приложения. Тем путем память сохранена, конструкция Квадратных объектов в Приложении может быть отложена к при необходимости, или они могут быть сделаны в конструкторах Приложения, значения по умолчанию или иначе. Конечно, деструктор должен уничтожить два Квадратных объекта, если бы они были созданы.

1
ответ дан 6 December 2019 в 12:55
поделиться

Необходимо использовать указатели вместо фактических объектов.

Используя указатели заставит Ваш класс вести себя так же к Java (он вынудит Вас явно инстанцировать его на методе "установки" или конструкторе). В Java каждый объект является ссылкой (подобный {но не равный} к указателю) и нет никакого эквивалента тому, при помощи чего Вы выполняете с C++:

class A {
   B b;
}

Надежда это помогает.

1
ответ дан 6 December 2019 в 12:55
поделиться

Почему Вы используете функцию setup/init? Используйте конструктора вместо этого, инициализирующие объекты являются смыслом существования конструктора. Объектами, которые могут существовать в неприменимых состояниях, является PItA, они требуют, чтобы каждая функция протестировала, можем ли мы делать что-либо хорошее с ними. Усильте их инвариант и запретите их существование, пока Вы не сможете полностью создать их.

Даже в Java, init/setup функции появляются мне как сомнительная практика.

1
ответ дан 6 December 2019 в 12:55
поделиться

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

(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
    ...
}
0
ответ дан 6 December 2019 в 12:55
поделиться

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

/**
    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
ответ дан 6 December 2019 в 12:55
поделиться

Нет НИКАКОГО выхода C++ способа сделать это.

C++ путь:

Сделайте то, что Вы хотите, я дам Вам столько веревки, сколько Вы хотите.
Человек ада! Вы могли даже подвесить себя с ним, я не собираюсь останавливать Вас!

Вы могли использовать указатели, но необходимо будет знать об утечках памяти! Необходимо определить, кто (как, в который класс/объект) владеет этим объектом, у кого есть исключительное право удалить его!

ИЛИ, Вы могли плагин сборщик "мусора" (я услышал, что существуют некоторые популярные, но никогда не пробовали никого сам), и затем работайте с указателями, как будто Вы были в Java.

0
ответ дан 6 December 2019 в 12:55
поделиться

Если Ваша установка () действительно не имеет никаких параметров и не возвращает значений, затем помещает ту функциональность в конструктора (я предполагаю, что Вы просто пропустили тех, которые для краткости).

При наличии установки () функция, которая должна быть вызвана после конструктора, не является лучшей, но может быть совершенно допустимой, когда выдача исключения в конструкторе не является опцией. Ваша установка () функция могла решить проблемы более гибким способом.

ОДНАКО: не позволяйте конструктору оставить объект в состоянии, которое вызовет проблемы позже, конкретно:

  • Инициализируйте все членские переменные указателя!! В целом необходимо установить все на некоторые значимые значения по умолчанию. В абсолютном минимуме имеют "сторожевой" разряд, чтобы определить, была ли установка () сделана и обрабатывает каждый случай, где это может укусить Вас.
  • В каждой функции, которая должна установить (), чтобы быть названной, удостоверьтесь, что она имеет, или назовите ее затем.
  • И, конечно, свободный все выделения в деструкторе!

Помещать его иначе: членская инициализация переменной похожа на наведение порядка в Вашем доме, прежде чем Ваши визиты Тещи - или сразу сделают это или поместят защиту на месте, чтобы позволить Вам, делают это, прежде чем это будет требоваться.

О, и не тратьте впустую указатели старающегося избегать большого количества времени в C++, но действительно удостоверьтесь, что Вы изучаете, как избежать ловушек.

0
ответ дан 6 December 2019 в 12:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: