C++ 基类从子类获取类型参数

问题描述 投票:0回答:1

我想要一个基类

Collection
定义以下接口。基类本身不应该实现这些数据,而是所有这些数据都应该由子类提供。

  • A型

    Member

  • 静态函数

    Member first_object()

  • 静态函数

    Member last_object()

  • 静态函数

    std::vector<Member> all_objects()

我的问题是我不知道如何拥有一个具有子类提供的类型的基类,即问题在于

Member
类型。

我能够提出以下实现(完整代码位于帖子底部):

template <typename Member>
struct CollectionBase {
    static Member first_object();
    static Member last_object();
    static std::vector<Member> all_objects();
};

struct CollectionA : CollectionBase<int> {
public:
    using Member = int;
private:
    static std::vector<Member> const objects;
public:
    static Member first_object() {
        return objects.front();
    }
    static Member last_object() {
        return objects.back();
    }
    static std::vector<Member> all_objects() {
        return objects;
    }
};

std::vector<CollectionA::Member> const CollectionA::objects = {1, 2, 3};

struct CollectionB : CollectionBase<std::string> {
public:
    using Member = std::string;
private:
    static std::vector<Member> const objects;
public:
    static Member first_object() {
        return objects.front();
    }
    static Member last_object() {
        return objects.back();
    }
    static std::vector<Member> all_objects() {
        return objects;
    }
};

std::vector<CollectionB::Member> const CollectionB::objects = {"One", "Two", "Three"};

template <typename Collection>
void do_stuff() {
    typename Collection::Member first_object = Collection::first_object();
    typename Collection::Member last_object = Collection::last_object();
    std::vector<typename Collection::Member> all_objects = Collection::all_objects();
    std::cout
        << "First object: " << first_object << std::endl
        << "Last object: " << last_object << std::endl
        << "All objects: " << all_objects << std::endl
    ;
}

int main() {
    do_stuff<CollectionA>();
    do_stuff<CollectionB>();
}

输出:

First object: 1
Last object: 3
All objects: { 1, 2, 3 }
First object: One
Last object: Three
All objects: { One, Two, Three }

这种行为正是我想要的。但是,我对必须始终手动传递

Member
类型参数感到不满意。事实上,在我的实际应用中,我有两种类型,这会变得很麻烦。

如果我的代码看起来有点类似于以下代码,我会更喜欢它:

struct CollectionBase {
    static typename Member;
    static Member first_object();
    static Member last_object();
    static std::vector<Member> all_objects();
};

struct CollectionA : CollectionBase {
public:
    using Member = int;
private:
    static std::vector<Member> const objects;
public:
    static Member first_object() {
        return objects.front();
    }
    static Member last_object() {
        return objects.back();
    }
    static std::vector<Member> all_objects() {
        return objects;
    }
};

std::vector<CollectionA::Member> const CollectionA::objects = {1, 2, 3};

struct CollectionB : CollectionBase {
public:
    using Member = std::string;
private:
    static std::vector<Member> const objects;
public:
    static Member first_object() {
        return objects.front();
    }
    static Member last_object() {
        return objects.back();
    }
    static std::vector<Member> all_objects() {
        return objects;
    }
};

std::vector<CollectionB::Member> const CollectionB::objects = {"One", "Two", "Three"};

template <typename Collection>
void do_stuff() {
    typename Collection::Member first_object = Collection::first_object();
    typename Collection::Member last_object = Collection::last_object();
    std::vector<typename Collection::Member> all_objects = Collection::all_objects();
    std::cout
        << "First object: " << first_object << std::endl
        << "Last object: " << last_object << std::endl
        << "All objects: " << all_objects << std::endl
    ;
}

int main() {
    do_stuff<CollectionA>();
    do_stuff<CollectionB>();
}

为了强调,这里是

git diff

@@ -1,11 +1,11 @@
-template <typename Member>
 struct CollectionBase {
+       static typename Member;
        static Member first_object();
        static Member last_object();
        static std::vector<Member> all_objects();
 };

-struct CollectionA : CollectionBase<int> {
+struct CollectionA : CollectionBase {
 public:
        using Member = int;
 private:
@@ -24,7 +24,7 @@ public:

 std::vector<CollectionA::Member> const CollectionA::objects = {1, 2, 3};

-struct CollectionB : CollectionBase<std::string> {
+struct CollectionB : CollectionBase {
 public:
        using Member = std::string;
 private:

可以这样做吗?


完整的工作示例(GodBolt Link):

#include <string>
#include <vector>
#include <iostream>

template <typename T>
std::ostream& operator<<(std::ostream& os, std::vector<T> const& v)
{
    os << "{ ";
    bool first = true;
    for (T const& t : v) {
        if (first)
            first = false;
        else
            os << ", ";
        os << t;
    }
    os << " }";
    return os;
}

template <typename Member>
struct CollectionBase {
    static Member first_object();
    static Member last_object();
    static std::vector<Member> all_objects();
};

struct CollectionA : CollectionBase<int> {
public:
    using Member = int;
private:
    static std::vector<Member> const objects;
public:
    static Member first_object() {
        return objects.front();
    }
    static Member last_object() {
        return objects.back();
    }
    static std::vector<Member> all_objects() {
        return objects;
    }
};

std::vector<CollectionA::Member> const CollectionA::objects = {1, 2, 3};

struct CollectionB : CollectionBase<std::string> {
public:
    using Member = std::string;
private:
    static std::vector<Member> const objects;
public:
    static Member first_object() {
        return objects.front();
    }
    static Member last_object() {
        return objects.back();
    }
    static std::vector<Member> all_objects() {
        return objects;
    }
};

std::vector<CollectionB::Member> const CollectionB::objects = {"One", "Two", "Three"};

template <typename Collection>
void do_stuff() {
    typename Collection::Member first_object = Collection::first_object();
    typename Collection::Member last_object = Collection::last_object();
    std::vector<typename Collection::Member> all_objects = Collection::all_objects();
    std::cout
        << "First object: " << first_object << std::endl
        << "Last object: " << last_object << std::endl
        << "All objects: " << all_objects << std::endl
    ;
}

int main() {
    do_stuff<CollectionA>();
    do_stuff<CollectionB>();
}

输出:

First object: 1
Last object: 3
All objects: { 1, 2, 3 }
First object: One
Last object: Three
All objects: { One, Two, Three }
c++ class inheritance interface
1个回答
0
投票

CollectionBase
课程根本没有必要。下面的代码也可以工作(GodBolt Link):

#include <string>
#include <vector>
#include <iostream>

template <typename T>
std::ostream& operator<<(std::ostream& os, std::vector<T> const& v)
{
    os << "{ ";
    bool first = true;
    for (T const& t : v) {
        if (first)
            first = false;
        else
            os << ", ";
        os << t;
    }
    os << " }";
    return os;
}

struct CollectionA {
public:
    using Member = int;
private:
    static std::vector<Member> const objects;
public:
    static Member first_object() {
        return objects.front();
    }
    static Member last_object() {
        return objects.back();
    }
    static std::vector<Member> all_objects() {
        return objects;
    }
};

std::vector<CollectionA::Member> const CollectionA::objects = {1, 2, 3};

struct CollectionB {
public:
    using Member = std::string;
private:
    static std::vector<Member> const objects;
public:
    static Member first_object() {
        return objects.front();
    }
    static Member last_object() {
        return objects.back();
    }
    static std::vector<Member> all_objects() {
        return objects;
    }
};

std::vector<CollectionB::Member> const CollectionB::objects = {"One", "Two", "Three"};

template <typename Collection>
void do_stuff() {
    typename Collection::Member first_object = Collection::first_object();
    typename Collection::Member last_object = Collection::last_object();
    std::vector<typename Collection::Member> all_objects = Collection::all_objects();
    std::cout
        << "First object: " << first_object << std::endl
        << "Last object: " << last_object << std::endl
        << "All objects: " << all_objects << std::endl
    ;
}

int main() {
    do_stuff<CollectionA>();
    do_stuff<CollectionB>();
}
© www.soinside.com 2019 - 2024. All rights reserved.