В качестве альтернативы KeyListener
рассмотрите использование действий и привязок клавиш , обсужденных здесь здесь . Выведенный из этого примера , программа ниже перемещает линию влево, вниз, вверх или вправо с помощью кнопок или клавиш.
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
/**
* @see https://stackoverflow.com/questions/6991648
* @see https://stackoverflow.com/questions/6887296
* @see https://stackoverflow.com/questions/5797965
*/
public class LinePanel extends JPanel {
private MouseHandler mouseHandler = new MouseHandler();
private Point p1 = new Point(100, 100);
private Point p2 = new Point(540, 380);
private boolean drawing;
public LinePanel() {
this.setPreferredSize(new Dimension(640, 480));
this.addMouseListener(mouseHandler);
this.addMouseMotionListener(mouseHandler);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(8,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
private class MouseHandler extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
drawing = true;
p1 = e.getPoint();
p2 = p1;
repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
drawing = false;
p2 = e.getPoint();
repaint();
}
@Override
public void mouseDragged(MouseEvent e) {
if (drawing) {
p2 = e.getPoint();
repaint();
}
}
}
private class ControlPanel extends JPanel {
private static final int DELTA = 10;
public ControlPanel() {
this.add(new MoveButton("\u2190", KeyEvent.VK_LEFT, -DELTA, 0));
this.add(new MoveButton("\u2191", KeyEvent.VK_UP, 0, -DELTA));
this.add(new MoveButton("\u2192", KeyEvent.VK_RIGHT, DELTA, 0));
this.add(new MoveButton("\u2193", KeyEvent.VK_DOWN, 0, DELTA));
}
private class MoveButton extends JButton {
KeyStroke k;
int dx, dy;
public MoveButton(String name, int code, final int dx, final int dy) {
super(name);
this.k = KeyStroke.getKeyStroke(code, 0);
this.dx = dx;
this.dy = dy;
this.setAction(new AbstractAction(this.getText()) {
@Override
public void actionPerformed(ActionEvent e) {
LinePanel.this.p1.translate(dx, dy);
LinePanel.this.p2.translate(dx, dy);
LinePanel.this.repaint();
}
});
ControlPanel.this.getInputMap(
WHEN_IN_FOCUSED_WINDOW).put(k, k.toString());
ControlPanel.this.getActionMap().put(k.toString(), new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
MoveButton.this.doClick();
}
});
}
}
}
private void display() {
JFrame f = new JFrame("LinePanel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.add(new ControlPanel(), BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new LinePanel().display();
}
});
}
}
C++ 11: Да!
C++ 11 и вперед имеет эту ту же функцию (названный конструкторы делегирования ).
синтаксис немного отличается от C#:
class Foo {
public:
Foo(char x, int y) {}
Foo(int y) : Foo('a', y) {}
};
C++ 03: Никакой
, К сожалению, нет никакого способа сделать это в C++ 03, но существует два способа моделировать это:
можно объединиться два (или больше) конструкторы через параметры по умолчанию:
class Foo {
public:
Foo(char x, int y=0); // combines two constructors (char) and (char, int)
// ...
};
Использование init метод для совместного использования общего кода:
class Foo {
public:
Foo(char x);
Foo(char x, int y);
// ...
private:
void init(char x, int y);
};
Foo::Foo(char x)
{
init(x, int(x) + 7);
// ...
}
Foo::Foo(char x, int y)
{
init(x, y);
// ...
}
void Foo::init(char x, int y)
{
// ...
}
См. запись FAQ C++ для ссылки.
Если я понимаю Ваш вопрос правильно, Вы спрашиваете, можно ли вызвать несколько конструкторов в C++?
, Если это - то, что Вы ищете, тогда нет - который не возможен.
Вы, конечно, можете иметь несколько конструкторов, каждого с уникальными подписями аргумента, и затем назвать ту, которую Вы хотите при инстанцировании нового объекта.
у Вас может даже быть один конструктор с принявшими значение по умолчанию аргументами на конце.
, Но Вы не можете иметь нескольких конструкторов, и затем назвать каждого из них отдельно.
Я бы предложил использовать метод private friend
, который реализует прикладную логику конструктора и вызывается различными конструкторами. Вот пример:
Предположим, у нас есть класс с именем StreamArrayReader
с некоторыми закрытыми полями:
private:
istream * in;
// More private fields
И мы хотим определить два конструктора:
public:
StreamArrayReader(istream * in_stream);
StreamArrayReader(char * filepath);
// More constructors...
Когда второй просто использует первый (и, конечно, мы не хотим дублировать реализацию первого). В идеале, хотелось бы сделать что-то вроде:
StreamArrayReader::StreamArrayReader(istream * in_stream){
// Implementation
}
StreamArrayReader::StreamArrayReader(char * filepath) {
ifstream instream;
instream.open(filepath);
StreamArrayReader(&instream);
instream.close();
}
Однако, это не разрешено в C ++. По этой причине мы можем определить метод закрытого друга следующим образом, который реализует то, что должен делать первый конструктор:
private:
friend void init_stream_array_reader(StreamArrayReader *o, istream * is);
Теперь этот метод (потому что это друг) имеет доступ к закрытым полям o
. Затем первый конструктор становится:
StreamArrayReader::StreamArrayReader(istream * is) {
init_stream_array_reader(this, is);
}
Обратите внимание, что это не создает несколько копий для вновь созданных копий. Вторым становится:
StreamArrayReader::StreamArrayReader(char * filepath) {
ifstream instream;
instream.open(filepath);
init_stream_array_reader(this, &instream);
instream.close();
}
То есть вместо того, чтобы один конструктор вызывал другого, оба вызывают частного друга!
Нет, в C++ Вы не можете вызвать конструктора от конструктора. Что можно сделать, как садок для кроликов, на который указывают:
Примечание, что в первом случае, Вы не можете уменьшить дублирование кода путем вызова одного конструктора от другого. У Вас могут, конечно, быть отдельное, частное/защищаемое, метод, который делает всю инициализацию, и позволяют конструктору главным образом иметь дело с обработкой аргумента.
Если вы хотите быть злым, вы можете использовать «новый» оператор на месте:
class Foo() {
Foo() { /* default constructor deliciousness */ }
Foo(Bar myParam) {
new (this) Foo();
/* bar your param all night long */
}
};
Кажется, работает для меня.
edit
Как указывает @ElvedinHamzagic, если Foo содержит объект, который выделил память, этот объект не может быть освобожден. Это еще более усложняет ситуацию.
Более общий пример:
class Foo() {
private:
std::vector<int> Stuff;
public:
Foo()
: Stuff(42)
{
/* default constructor deliciousness */
}
Foo(Bar myParam)
{
this->~Foo();
new (this) Foo();
/* bar your param all night long */
}
};
Выглядит немного менее элегантно, наверняка. @ Решение JohnIdol намного лучше.
Стоит отметить, что вы можете вызвать конструктор родительского класса в вашем конструкторе, например:
class A { /* ... */ };
class B : public A
{
B() : A()
{
// ...
}
};
Но, нет, вы не можете вызвать другой конструктор того же класса.
Нет, Вы не можете назвать одного конструктора от другого в C++ 03 (названным конструктором делегирования).
Это изменилось в C++ 11 (иначе C++ 0x), который добавил поддержку следующего синтаксиса:
(пример, взятый от Википедия )
class SomeType
{
int number;
public:
SomeType(int newNumber) : number(newNumber) {}
SomeType() : SomeType(42) {}
};
Я верю вам может вызвать конструктор из конструктора. Он скомпилируется и запустится. Я недавно видел, как кто-то делал это, и это работало как в Windows, так и в Linux.
Это просто не то, что вы хотите. Внутренний конструктор создаст временный локальный объект, который будет удален после возврата внешнего конструктора. Они также должны быть разными конструкторами, иначе вы создадите рекурсивный вызов.
Ссылка: https: // isocpp. org / wiki / faq / ctors # init-methods