C++的构造函数是个很神奇的东东, 今天总结一下, 还是先来一个例子先:
点击(此处)折叠或打开
-
#include <iostream>
-
using namespace std;
-
-
template<typename T>
-
class Node{
-
//Node<T> nodemyself;
-
public:
-
Node();
-
Node(T& d);
-
T c;
-
Node<T> *next,*pref;
-
};
-
-
template<typename T>
-
Node<T>::Node()
-
{}
-
template<typename T>
-
Node<T>::Node(T& d):c(d),next(0),pref(0)
-
{}
-
-
-
template<typename T>
-
class List{
-
Node<T> *first, *last;
-
Node<T> nodemyself;
-
List<T> *myself;
-
public:
-
List();
-
void add(T& c);
-
void remove(T& c);
-
Node<T>* find(T& c);
-
void print();
-
~List();
-
};
-
-
template<typename T>
-
List<T>::List():first(0),last(0)
-
{}
-
-
template<typename T>
-
void List<T>::add(T& n)
-
{
-
Node<T>* p = new Node<T>(n);
-
p->next = first;
-
first = p;
-
(last?p->next->pref:last) = p;
-
}
-
-
template<typename T>
-
void List<T>::remove(T& n)
-
{
-
Node<T> *p = find(n);
-
if(!p) return;
-
(p->next?p->next->pref:last) = p->pref;
-
(p->pref?p->pref->next:first) = p->next;
-
delete p;
-
}
-
-
template<typename T>
-
Node<T>* List<T>::find(T& n)
-
{
-
for(Node<T> *p = first; p;p=p->next)
-
{
-
if(p->c == n) return p;
-
}
-
return 0;
-
}
-
-
template<typename T>
-
List<T>::~List()
-
{
-
for(Node<T> *p; p = first;delete p)
-
first = first->next;
-
}
-
-
template<typename T>
-
void List<T>::print()
-
{
-
for(Node<T>* p=first;p;p=p->next)
-
cout<< p->c<<" ";
-
cout<< "\n";
-
}
-
-
int main()
-
{
-
//double a1 = 1.1;
-
//Node<double> nodemyself(a1);
-
List<double> dList;
-
double a = 3.6;
-
double b = 5.8;
-
dList.add(a);
-
dList.add(b);
-
dList.print();
-
-
int c=5;
-
int d=8;
-
List<int> iList;
-
iList.add(c);
-
iList.add(d);
-
iList.print();
- }
这是上一篇博文里面的例子, 一样是出自
第一个知识点:
类或结构体的前向声明只能用来定义指针对象,因为编译到这里时还没有发现定义,不知道该类或者结构的内部成员,没有办法具体的构造一个对象. 就好比如说, 我想在某个类a里面, 定义一个类a自己的实例, 那是会报错滴. 以开头那个例子来说, 比如说把第6行注释放开, 或者第26行改为List<T> myself;就会得到类似于下面这样的编译报错.
点击(此处)折叠或打开
-
main.cpp: In instantiation of 'Node<double>':
-
main.cpp:25: instantiated from 'List<double>'
-
main.cpp:88: instantiated from here
-
main.cpp:6: error: 'Node<T>::nodemyself' has incomplete type
-
main.cpp:5: error: declaration of 'class Node<double>'
-
main.cpp: In instantiation of 'List<double>':
-
main.cpp:88: instantiated from here
-
main.cpp:26: error: 'List<T>::myself' has incomplete type
-
main.cpp:23: error: declaration of 'class List<double>'
-
main.cpp: In instantiation of 'Node<int>':
-
main.cpp:25: instantiated from 'List<int>'
-
main.cpp:97: instantiated from here
-
main.cpp:6: error: 'Node<T>::nodemyself' has incomplete type
-
main.cpp:5: error: declaration of 'class Node<int>'
-
main.cpp: In instantiation of 'List<int>':
-
main.cpp:97: instantiated from here
-
main.cpp:26: error: 'List<T>::myself' has incomplete type
- main.cpp:23: error: declaration of 'class List<int>
第二个知识点: 当某个类只定义了一个构造函数包含非常量引用型形参时, 系统会默认生成一个常量型引用形参. 这样的话, 编码的时候就一定要注意在定义类对象实例的时候, 添加上对应初始化参数. 还是以上面那个例子为例:
屏蔽掉第8行, 第14-16行, 让模版类只包含有一个非常量引用型形参的构造函数Node<T>::Node(T& d):c(d),next(0),pref(0) ,这样一来, 继续运行会发现有如下错误:
点击(此处)折叠或打开
-
main.cpp: In constructor 'List<T>::List() [with T = double]':
-
main.cpp:88: instantiated from here
-
main.cpp:37: error: no matching function for call to 'Node<double>::Node()'
-
main.cpp:18: note: candidates are: Node<T>::Node(T&) [with T = double]
-
main.cpp:5: note: Node<double>::Node(const Node<double>&)
-
main.cpp: In constructor 'List<T>::List() [with T = int]':
-
main.cpp:97: instantiated from here
-
main.cpp:37: error: no matching function for call to 'Node<int>::Node()'
-
main.cpp:18: note: candidates are: Node<T>::Node(T&) [with T = int]
- main.cpp:5: note: Node<int>::Node(const Node<int>&)
Node(T& d); 而在List类中定义的成员函数却是这样定义的Node<T> nodemyself; 这个定义没带任何参数, 因此就没有构造函数来构造它了, 因此报错! 这也就是为什么我们屏蔽掉第8行, 第14-16行会报错的原因.
我们再证实一下, 把第25行Node<T> nodemyself; 改为Node<T> nodemyself(T); 让它强制性的符合Node的构造函数Node(T& d); 发现果然可以编译通过了.
第三个知识点:
这是由第二个知识点引申来的, 当某个类模版template class a中, 包含有由其它类模版template class b定义的成员变量时, 在定义a的构造函数的时候, 成员变量b的初始值不能放在函数名跟冒号的那个后面去初始化, 而是应该放到函数体里面(具体为什么需要这样我也没搞明白).
刚才第二点中, 我们已经把第25行Node<T> nodemyself; 改为Node<T> nodemyself(T); 让它强制性的符合Node的构造函数Node(T& d); 因为这个nodemyself毕竟是属于类模版List的成员函数, 那么我就想能否在成员函数中初始化一下它, 于是乎我把代码改为了下面这样:
(姑且称之为例2吧)
点击(此处)折叠或打开
-
#include <iostream>
-
using namespace std;
-
-
template<typename T>
-
class Node{
-
Node<T> *nodemyself;
-
public:
-
// Node();
-
Node(T& d);
-
T c;
-
Node<T> *next,*pref;
-
};
-
-
//template<typename T>
-
//Node<T>::Node()
-
//{}
-
template<typename T>
-
Node<T>::Node(T& d):c(d),next(0),pref(0)
-
{}
-
-
-
template<typename T>
-
class List{
-
private:
-
Node<T> *first, *last;
-
Node<T> nodemyself(T);
-
Node<T> *nodemyself2;
-
List<T> *myself;
-
public:
-
List();
-
List(T &a);
-
void add(T& c);
-
void remove(T& c);
-
Node<T>* find(T& c);
-
void print();
-
~List();
-
};
-
-
template<typename T>
-
List<T>::List():first(0),last(0)
-
{}
-
-
template<typename T>
-
List<T>::List(T &a):first(0),last(0),nodemyself(a)
-
{
-
//nodemyself = a;
-
}
-
-
template<typename T>
-
void List<T>::add(T& n)
-
{
-
Node<T>* p = new Node<T>(n);
-
p->next = first;
-
first = p;
-
(last?p->next->pref:last) = p;
-
}
-
-
template<typename T>
-
void List<T>::remove(T& n)
-
{
-
Node<T> *p = find(n);
-
if(!p) return;
-
(p->next?p->next->pref:last) = p->pref;
-
(p->pref?p->pref->next:first) = p->next;
-
delete p;
-
}
-
-
template<typename T>
-
Node<T>* List<T>::find(T& n)
-
{
-
for(Node<T> *p = first; p;p=p->next)
-
{
-
if(p->c == n) return p;
-
}
-
return 0;
-
}
-
-
template<typename T>
-
List<T>::~List()
-
{
-
for(Node<T> *p; p = first;delete p)
-
first = first->next;
-
}
-
-
template<typename T>
-
void List<T>::print()
-
{
-
for(Node<T>* p=first;p;p=p->next)
-
cout<< p->c<<" ";
-
cout<< "\n";
-
}
-
-
int main()
-
{
-
//double a1 = 1.1;
-
//Node<double> nodemyself(a1);
-
List<double> dList;
-
double a = 3.6;
-
double b = 5.8;
-
dList.add(a);
-
dList.add(b);
-
dList.print();
-
-
int c=5;
-
int d=8;
-
List<int> iList;
-
iList.add(c);
-
iList.add(d);
-
iList.print();
- }
点击(此处)折叠或打开
-
main.cpp: In constructor 'List<T>::List(T&)':
- main.cpp:44: error: class 'List<T>' does not have any field named 'nodemyself
点击(此处)折叠或打开
-
template<typename T>
-
List<T>::List(T &a):first(0),last(0)
-
{
-
nodemyself = a;// 或者这样也行nodemyself(a);
- }
但是注意了, 如果我定义的是一个由类模版定义的指针, 如例2中的Node<T> *nodemyself2; 那么是可以用下面这种方式去构造的(放到冒号后面), 如下:
点击(此处)折叠或打开
-
template<typename T>
-
List<T>::List(T &a):first(0),last(0),nodemyself2(&a)
- {}
构造函数博大精深, 牵涉到模版类这种饶人的玩意的时候, 更是要注意再注意!!!