混合数组初始化器和继承

时间:2019-04-24 17:40:09

标签: c++

我有一个定义如下的car_table数组:

struct car_traits_type;

enum { U = 0, A = 1, M = 2 };

struct car_type {
    const char * name;
    int type;
    car_traits_type * traits;
};

struct car_traits_type {
    const char * color;
};

struct automatic_traits_type : car_traits_type {
    automatic_traits_type(const char * color) : car_traits_type{color}, top_speed{55} {}
    automatic_traits_type(const char * color, int _top_speed) : car_traits_type{color}, top_speed{_top_speed} {}
    int top_speed;
};

struct car_type car_table[MAX_CARS] = {
    {"Honda",   A, new automatic_traits_type{"blue"}     },
    {"Porsche", U, new car_traits_type{"green"}          },
    {"Toyota",  A, new automatic_traits_type{"blue", 65} },
    { nullptr,  0, nullptr                               }
};

在驱动程序代码中,我键入将特征指针投射到派生类:

car = car_lookup("Porsche");
printf("%s is painted %s\n",car_table[car].name, car_table[car].traits->color);

int car2 = car_lookup("Toyota");
printf("%s has a top speed of %d\n",car_table[car2].name, static_cast<automatic_traits_type *>(car_table[car2].traits)->top_speed);

这正常工作并执行。

我想创建一个实用函数或宏来执行类型转换,以使我的驱动程序代码不再那么冗长。我尝试使用枚举来捕获类型,以便可以在驱动程序代码中完成适当的类型转换,即:

#define CAR_TRAITS( type, car ) (( (type) == 1) ? \
   static_cast<automatic_traits_type *>(car_table[(car)].traits) : \
   static_cast<car_traits_type *>(car_table[(car)].traits)) 

int car3 = car_lookup("Honda");
int type = car_table[car3].type;

printf("%d type", type);
printf("%s has a top speed of %d\n",car_table[car3].name, CAR_TRAITS(type,car3)->top_speed);

但是,出现以下编译错误:

module2.cpp:30:86: error: ‘struct car_traits_type’ has no member named ‘top_speed’
     printf("%s has a top speed of %d\n",car_table[car3].name, CAR_TRAITS(type,car3)->top_speed);

我希望对CAR_TRAITS宏的求值类型将表达式强制转换为automatic_traits_type *

3 个答案:

答案 0 :(得分:2)

三元表达式将具有一个返回类型。我猜想automatic_traits_type*会自动转换为car_traits_type*以容纳this

更好的方法是将继承用作接口。例如。拥有get_color虚拟功能,而不是访问实现细节。

答案 1 :(得分:0)

您的原型有很多需要改进的地方。即

  1. 最糟糕的是,使用原始指针很可能导致内存泄漏。让我们改用std::unique_ptrenum class
  2. 作用域枚举(std::array)与传统的枚举相比具有多个优点。
  3. 让我们使用RTTI定义汽车特征类型。我们可以将枚举保留为奖励。
  4. 不要忘记基类中的虚拟析构函数。
  5. 对单参数构造函数进行明确显示可以防止意外的强制转换。
  6. 使用dynamic_cast代替传统数组也有一些优点。
  7. 例如,可以进一步改进设计。您可以添加虚拟函数来打印值,而不是使用#include <iostream> #include <memory> struct car_traits_type; enum class CarType { U = 0, A = 1, M = 2 }; struct car_type { car_type(std::string name_, std::unique_ptr<car_traits_type> traits_) : name(std::move(name_)), traits(std::move(traits_)) {} std::string name; std::unique_ptr<car_traits_type> traits; }; struct car_traits_type { car_traits_type() = default; explicit car_traits_type(std::string color) : color(std::move(color)) {} virtual ~car_traits_type() = default; virtual CarType type() const { return CarType::U; } std::string color; }; struct automatic_traits_type : car_traits_type { automatic_traits_type() = default; explicit automatic_traits_type(std::string color, int _top_speed = 55) : car_traits_type(std::move(color)), top_speed(_top_speed) {} CarType type() const override { return CarType::A; } int top_speed; }; std::array<car_type, 3> cars = { car_type{"Honda", std::make_unique<automatic_traits_type>("blue")}, car_type{"Porsche", std::make_unique<car_traits_type >("green")}, car_type{"Toyota", std::make_unique<automatic_traits_type>("blue", 65)} }; int main() { for (auto& ct : cars) { std::cout << ct.name; if (ct.traits) { std::cout << ' ' << static_cast<int>(ct.traits->type()) << ' ' << ct.traits->color; if (auto* at = dynamic_cast<automatic_traits_type*>(ct.traits.get())) std::cout << ' ' << at->top_speed; } std::cout << '\n'; } return 0; } ...

总结:使用现代内存管理和虚拟类层次结构,可以解决您的问题。

请看下面的代码作为工作示例(它需要C ++ 14,希望您的编译器支持它)

import schedule
import time
import datetime
import uuid

from flask import Flask, request
from multiprocessing import Process

app = Flask(__name__)
t = None
job_timer = None

def run_job(id):
    """ sample job with parameter """
    global job_timer
    print("timer job id={}".format(id))
    print("timer: {:.4f}sec".format(time.time() - job_timer))
    job_timer = time.time()

def run_schedule():
    """ infinite loop for schedule """
    global job_timer
    job_timer = time.time()
    while 1:
        schedule.run_pending()
        time.sleep(1)

@app.route('/timer/<string:status>')
def mytimer(status, nsec=10):
    global t, job_timer
    if status=='on' and not t:
        schedule.every(nsec).seconds.do(run_job, str(uuid.uuid4()))
        t = Process(target=run_schedule)
        t.start()
        return "timer on with interval:{}sec\n".format(nsec)
    elif status=='off' and t:
        if t:
            t.terminate()
            t = None
            schedule.clear()
        return "timer off\n"
    return "timer status not changed\n"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

答案 2 :(得分:0)

我不确定100%是否理解您的动机,所以让我假设您想对已定义的类型进行尽可能小的更改,仅在调用者站点上修复强制转换。此外,这里:

int car2 = car_lookup("Toyota");
printf("%s has a top speed of %d\n",car_table[car2].name, static_cast<automatic_traits_type *>(car_table[car2].traits)->top_speed); 

呼叫者需要知道"Toyota"有一个top_speed,否则它们会在运行时出现问题。假设呼叫者知道他们得到的汽车有top_speed。在那种情况下,我可能会使用

int get_top_speed(const car& c) {
    return static_cast<automatic_traits_type *>(c.traits)->top_speed;
}