使用C++17从另一个构造函数调用不同参数类型的构造函数

huangapple go评论86阅读模式
英文:

Call constructor with different argument types from another constructor in C++17

问题

I have a class called Date:

class Date {
public:
    explicit Date(const int day = 1, const int month = 1, const int year = 0) {
        this->Construct(day, month, year);
    }

    explicit Date(const string &date_as_string) {
        int day, month, year;
        // parsing the string date_as_string
        this->Construct(day, month, year);
    }

private:
    void Construct(const int day, const int month, const int year) {
        // constructing the Date object
    }
};

有没有一种方法可以直接从Date(string&)调用Date(int, int, int),从而避免编写单独的函数?

UPD:

一些澄清。我的类应该如下所示:

class Date {
public:
    explicit Date(const int day = 1, const int month = 1, const int year = 0) {
        // constructing the Date object
    }

    explicit Date(const string &date_as_string) {
        int day, month, year;
        // 解析字符串 date_as_string
        // 调用 Date(day, month, year) 来构造 Date 对象
    }

  // 其他任何函数

private:
    // 私有字段
};

并且以下代码应该编译通过:

Date date("some_string_containing_date");
Date date(1, 1, 0);
英文:

I have a class called Date:

class Date {
public:
    explicit Date(const int day = 1, const int month = 1, const int year = 0) {
        this->Construct(day, month, year);
    }

    explicit Date(const string &date_as_string) {
        int day, month, year;
        // parsing the string date_as_string
        this->Construct(day, month, year);
    }

private:
    void Construct(const int day, const int month, const int year) {
        // constructing the Date object
    }
};

Is there a way to call Date(int, int, int) directly from Date(string&), thus avoiding writing a separate function?

UPD:

Some clarification. My class should look like:

class Date {
public:
    explicit Date(const int day = 1, const int month = 1, const int year = 0) {
        // constructing the Date object
    }

    explicit Date(const string &date_as_string) {
        int day, month, year;
        // parsing the string date_as_string
        // call Date(day, month, year) to construct the Date object
    }

  // any other functions

private:
    // private fields
};

And the following code should compile:

Date date("some_string_containing_date");
Date date(1, 1, 0);

答案1

得分: 3

可以在另一个构造函数的基础上定义一个构造函数。不过,我认为你需要使用一些额外的函数来实现它。

调用同一类的另一个构造函数的构造函数被称为“委托构造函数”,并使用与成员初始化列表相同类型的语法,但使用类自身的名称而不是基类和成员的名称:

ClassName::ClassName(SomeParam1 p1, SomeParam2 p2)
    : ClassName(arg_expr1, arg_expr2, arg_expr3)
{ /* 在目标构造函数完成后可以添加任何其他逻辑 */ }

但由于需要中间对象 date_as_struct,这个情况有点棘手。或者根据更新后的问题,只需在进入另一个构造函数之前进行一些解析。我会通过创建一个接受 Date_as_struct 的额外私有构造函数来解决这个问题:

class Date {
public:
    explicit Date(int day = 1, int month = 1, int year = 0); 
    explicit Date(const string &date_as_string);
    /* ... */
private:
    struct Date_as_struct {
        int day;
        int month;
        int year;
    };

    explicit Date(const Date_as_struct&);

    static Date_as_struct ParseStringContainingDate(const std::string&);
};

// 对于字符串构造函数,只需这样:
Date::Date(const std::string& date_as_string)
    : Date(ParseStringContainingDate(date_as_string))
{}

Date(const Date_as_struct&) 构造函数可以非常容易地委托给 Date(int, int, int),或者反之,取决于实际成员初始化的自然方式。

英文:

Yes, you can define one constructor in terms of another. No, I don't think you can do it without some additional function.

A constructor which invokes another constructor of the same class is called a "delegating constructor", and uses the same sort of syntax as a member initializer list, but using the class's own name instead of its base classes and members:

ClassName::ClassName(SomeParam1 p1, SomeParam2 p2)
    : ClassName(arg_expr1, arg_expr2, arg_expr3)
{ /* any other logic after the target constructor finishes */ }

But this case is a bit tricky because of the need for the intermediate object date_as_struct. Or with the updated question, just the need to do some parsing before entering another constructor. I'd solve this one by making an additional private constructor which takes the Date_as_struct:

class Date {
public:
    explicit Date(int day = 1, int month = 1, int year = 0); 
    explicit Date(const string &date_as_string);
    /* ... */
private:
    struct Date_as_struct {
        int day;
        int month;
        int year;
    };

    explicit Date(const Date_as_struct&);
    
    static Date_as_struct ParseStringContainingDate(const std::string&);
};

Date_as_struct and ParseStringContainingDate are declared here as private, since it sounds like nothing else will really use them.

Then for the string constructor, you just have

Date::Date(const std::string& date_as_string)
    : Date(ParseStringContainingDate(date_as_string))
{}

The Date(const Date_as_struct&) constructor can very easily delegate to Date(int, int, int) or vice versa, whichever is more natural for the actual member initialization.

huangapple
  • 本文由 发表于 2020年1月7日 01:29:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/59616459.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定