简体   繁体   中英

c++ How do i call a constructor of an interior class with templates?

I want to ceate an Nach obeject by calling Nach(3, a) where a is Mat object. Some thing fails at this point. ( Line: Graph::Nach h = Graph::Nach(3,a); )

Nach is defined as in interior class of Graph. Graph uses two templates. Nach stands for a neighbor, Mat for material, Masch for machine.

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

class Mat {

    public:
        int _id;
        int _type;
        double _amount;

        Mat (int id, int type, double amount );
};
Mat::Mat(int id, int type, double amount){
    std::cout<<"Mat constuktor used"<<std::endl;
    _id = id; _type = type; _amount = amount;
};




class Masch {
    public:
        int _id;
        int _rez;
        double _count;

        Masch (int id, int rez, double count );

};
Masch::Masch(int id, int rez, double count){
    std::cout<<"Masch constuktor used"<<std::endl;
    _id = id; _rez = rez; _count = count;
};


template <class V, class E>
class Graph {
    public:
        class Nach {
            public:
                int _id;
                Mat _e;

                Nach(int id, Mat e);
        };

        int num;
        std::vector<V> nodes;
        std::vector<std::vector<Nach>> _nach;

        void addVertex(V t);
        void addEdge(V a, V b, E e);

        Graph();


};
template <class V, class E> Graph<V,E>::Graph(){
    std::cout<<"Graph constuktor used"<<std::endl;
    num = 0;    
}
template <class V, class E> Graph<V,E>::Nach::Nach(int id, Mat e){
    std::cout<<"Nach constuktor used"<<std::endl;
    _id = id; _e = e;
}
template <class V, class E> void Graph<V,E>::addVertex(V t){
    nodes.push_back(t);
    _nach.push_back(std::vector<Nach>());
    num++;
}
template <class V, class E> void Graph<V,E>::addEdge(V a, V b, E e){
    int i = a._id;
    int j = b._id;
    //Graph<V, E>::Nach x(3, e);
    //_nach[j].push_back(Nach(i,e));

}

int main (){

    Mat a= Mat(0,1,0.1); 
    //Mat b= Mat(1,1,0.3);

    Masch c = Masch(0,0,0.1);

    Graph <Masch, Mat> g = Graph<Masch, Mat>();

    //std::cout << a+b <<std::endl;
    //std::cout << c <<std::endl;

    Graph<Masch, Mat>::Nach h = Graph<Masch, Mat>::Nach(3,a);

    g.addVertex(c);
    g.addVertex(c);

    //g.addEdge(c,c,a);


    return 0;

}

I expect to creat an instance of the Nach class.

But it raises an calling error of the constructor of Mat. I dont see where "Mat" is called by the the call of "Nach"

Error massenge

Hello.cpp: In instantiation of ‘Graph<V, E>::Nach::Nach(int, Mat) [with V = Masch; E = Mat]’:
Hello.cpp:94:57:   required from here
Hello.cpp:65:65: error: no matching function for call to ‘Mat::Mat()’
 template <class V, class E> Graph<V,E>::Nach::Nach(int id, Mat e){
                                                                 ^
Hello.cpp:16:1: note: candidate: Mat::Mat(int, int, double)
 Mat::Mat(int id, int type, double amount){
 ^
Hello.cpp:16:1: note:   candidate expects 3 arguments, 0 provided
Hello.cpp:7:7: note: candidate: constexpr Mat::Mat(const Mat&)
 class Mat {
       ^
Hello.cpp:7:7: note:   candidate expects 1 argument, 0 provided
Hello.cpp:7:7: note: candidate: constexpr Mat::Mat(Mat&&)
Hello.cpp:7:7: note: candidate expects 1 argument, 0 provided

When you invoke the Nach constructor, each of the members are default constructed and then the constructor body is executed. Mat does not have a default constructor. You cannot see the call to Mat() mentioned in the error message because the call is being generated by the compiler. The solution is to use an initialisation list instead of constructing then assigning. Most of the time, a constructor body should be empty.

template <class V, class E>
Graph<V, E>::Nach::Nach(int id, Mat e)
  : _id{id}, _e{e} {}

This constructs the members directly instead of first default constructing them and then assigning to them (like you would in Java or something). You should always use initialisation lists.

There are a few other things I should mention.

  • Using class in template parameter lists is a little old fashioned. class is allowed for backwards compatibility so it should be avoided. class was originally used to avoid adding another keyword to the language, typename was added later.
  • Beginning identifiers with one or more _underscores_ usually isn't a good idea. This is because identifiers beginning with underscores are reserved for the implementation so you could get collisions.
  • When using an initialisation list, the constructor parameters may have the same names as the members so the following is allowed and will behave as expected. There's rarely any reason to put underscores (or any other character sequence) in member names to avoid collisions.

This is how I would implement the constructor.

template <typename V, typename E>
Graph<V, E>::Nach::Nach(const int id, const Mat e)
  : id{id}, e{e} {}

when creating Nach nested class, you need to create a Mat (with default constructor) as you initialize the _e member inside the constructor.

You should try to rewrite your constructor to copy the passed mat:

template <class V, class E> Graph<V,E>::Nach::Nach(int id, Mat e): _e(e) {
    // _e is now initialize from a e copy before entering here.
    std::cout<<"Nach constuktor used"<<std::endl;
    _id = id;  // this could be moved as welll
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM