abstract class 指针参数的默认值

Default value for abstract class pointer parameter

我正在尝试做这样的事情:

class Movement {
public:
    virtual void move() = 0;
};

class Walk : public Movement {
public:
    void move() { cout << "walking"; }
};

class Run : public Movement {
public:
    void move() { cout << "run"; }
};
class Animal {
public:
    virtual void print();
};

class Human : public Animal {
public:
    void print() { cout << "Human"; }
};

class Lion : public Animal {
public:
    void print() { cout << "Lion"; }
};
class Model {
    Animal* animal;
    Movement* movement;

public:
    Model(Animal* animal = new Human(), Movement* movement = new Walk()) {
        this->animal = animal;
        this->movement = movement;
    }
    void print() {
        cout << "This Model consist of one: ";
        animal->print();
        cout << ", which is: ";
        movement->move();
    }
};
int main() {
    Model first = Model(), second = Model(new Lion(), new Run());
    first.print();
    cout << endl;
    second.print();
    return 0;
}

我们如何设置抽象 class 指针的默认值以及如何像从 main 那样将它们作为参数传递?

我也希望能够像这样仅在一行中传递来自 main 的参数,而无需之前进行初始化。

任何人都可以帮助我在 C++ 中如何做这些事情吗?

我已经尝试和搜索了很多但没有运气。

我正在寻找一种解决方法来做这样的事情,其中​​我们使用抽象 classes 作为其他 classes 的参数。

我知道不能将对象分配给指针,我只是不知道该怎么做才能满足我的要求,抽象 class 作为具有默认值的参数。

这是我对精确代码的最新尝试,但不幸的是 new,有谁知道如何摆脱 new 并达到预期的结果?

注:
我的实际代码相当复杂,基本上使用抽象 class 进行多态性并将这些抽象 class 作为参数传递给另一个具有默认参数的 class ,如果有 ANY 其他方式来做类似的事情我真的很感激你的帮助。

这真是一道设计题。在 Modelclass 设计中,您要么需要决定对象所有权,要么将决定推迟到调用代码。在后一种情况下,你不能有默认参数(除非你想有全局常量 HumanWalk,但我不推荐它)。

获得默认参数的一种方法是确定 Model 拥有 AnimalMovement 的独占所有权,并将 unique_ptr 存储给它们。像这样:

class Model {
    unique_ptr<Animal> animal;
    unique_ptr<Movement> movement;

public:
  Model(unique_ptr<Animal> animal = make_unique<Human>(), unique_ptr<Movement> movement = make_unique<Walk>()){ 
    this->animal = std::move(animal);
    this->movement = std::move(movement);
  }
  void print() {
    cout << "This Model consist of one: ";
    animal->print();
    cout << ", which is: ";
    movement->move();
  }
};

int main() {
  Model first/*no () here!*/, second(make_unique<Lion>(), make_unique<Run>()); 
  first.print();
  cout << endl;
  second.print();
  return 0;
}

你的问题是编译错误吗?有多种方法可以解决编译错误,但鉴于您的问题是关于从抽象 classes 继承,我将重点关注它。

首先,根据规定,您的 Animal class 是 而不是 摘要 class .抽象 class 无法实例化,因为它的所有方法都是纯虚拟的。在 C++ 中,纯虚函数由 virtual 关键字前缀指定, 在其定义中以 = 0 为后缀。例如

...
virtual void print() = 0;
...

通过将您的 Animal class 抽象为 class:

可以编译以下代码
#include <iostream>
using namespace std;

class Movement {
 public:
  virtual void move() = 0;
};

class Walk : public Movement {
 public:
  void move() { cout << "walking"; }
};

class Run : public Movement {
 public:
  void move() { cout << "run"; }
};

class Animal {
 public:
  virtual void print() = 0;
};

class Human : public Animal {
 public:
  void print() { cout << "Human"; }
};

class Lion : public Animal {
 public:
  void print() { cout << "Lion"; }
};

class Model {
  Animal* animal;
  Movement* movement;

 public:
  Model(Animal* animal = new Human(), Movement* movement = new Walk()) {
    this->animal = animal;
    this->movement = movement;
  }
  void print() {
    cout << "This Model consist of one: ";
    animal->print();
    cout << ", which is: ";
    movement->move();
  }
};

int main() {
  Model first = Model(),
        second = Model(new Lion(), new Run());
  first.print();
  cout << endl;
  second.print();
  return 0;
}

顺便说一下,您的代码也可以通过为 Animal::print() 提供一个实现来编译。以下代码也是可编译的,但是 Animal 不是 抽象 class 因为它提供了 Animal::print() 而不是在其后缀 = 0:

#include <iostream>
using namespace std;

class Movement {
 public:
  virtual void move() = 0;
};

class Walk : public Movement {
 public:
  void move() { cout << "walking"; }
};

class Run : public Movement {
 public:
  void move() { cout << "run"; }
};

class Animal {
 public:
  virtual void print() {};
};

class Human : public Animal {
 public:
  void print() { cout << "Human"; }
};

class Lion : public Animal {
 public:
  void print() { cout << "Lion"; }
};

class Model {
  Animal* animal;
  Movement* movement;

 public:
  Model(Animal* animal = new Human(), Movement* movement = new Walk()) {
    this->animal = animal;
    this->movement = movement;
  }
  void print() {
    cout << "This Model consist of one: ";
    animal->print();
    cout << ", which is: ";
    movement->move();
  }
};

int main() {
  Model first = Model(),
        second = Model(new Lion(), new Run());
  first.print();
  cout << endl;
  second.print();
  return 0;
}

否则,从概念上讲,您正在做的事情在 C++ 中完全可行:将默认值分配给某个函数参数列表中的基 class 指针。


重要:正如评论者正确指出的那样,您编码的模式很危险:您的界面使得用户可以 可选地 提供一个Animal 实例。问题是:如果 Model 创建者拥有,那么可以合理地论证他正确地拥有该对象。如果他不这样做,那么您的构造函数 创建一个新的 Animal 实例,但 Model 既不会取得该对象的所有权,也不会提供接口用户可以获得新 Animal 实例的所有权。因此,这会造成内存泄漏。同样,代码风险是 Model 构造函数中使用的 Animal 实例的所有权不明确。

我想我想出了适合我的情况的最佳解决方案。

#include <iostream>
#include <memory>
using namespace std;
class Movement {
 public:
  virtual void move() = 0;
  virtual unique_ptr<Movement> movement() const = 0;
};

class Walk : public Movement {
 public:
  void move() { cout << "walking"; }
  unique_ptr<Movement> movement() const { return make_unique<Walk>(); }
};

class Run : public Movement {
 public:
  void move() { cout << "run"; }
  unique_ptr<Movement> movement() const { return make_unique<Run>(); }
};
class Animal {
 public:
  virtual void print() = 0;
  virtual unique_ptr<Animal> animal() const = 0;
};

class Human : public Animal {
 public:
  void print() { cout << "Human"; }
  unique_ptr<Animal> animal() const { return make_unique<Human>(); }
};

class Lion : public Animal {
 public:
  void print() { cout << "Lion"; }
  unique_ptr<Animal> animal() const { return make_unique<Lion>(); }
};
class Model {
  unique_ptr<Animal> animal;
  unique_ptr<Movement> movement;

 public:
  Model(const Animal& animal = Human(), const Movement& movement = Walk()) {
    this->animal = animal.animal();
    this->movement = movement.movement();
  }
  void print() {
    cout << "This Model consist of one: ";
    animal->print();
    cout << ", which is: ";
    movement->move();
  }
};
int main() {
  Model first = Model(), second = Model(Lion(), Run());
  first.print();
  cout << endl;
  second.print();
  return 0;
}