论坛首页 编程语言技术论坛

C++拷贝构造函数与运算符重载

浏览 4232 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-05-26  
C++
拷贝构造函数与运算符的重载
* 多态
  - 前堤:继承,虚函数,指针或引用
  - 类型转换 : dynamic_cast 把父类*转换成子类*
  - 纯虚函数 : 保证此函数一定不会被执行,抽象类,不能创建对象.

* 友元
  - 内部授权,不是成员,这一点很重要,因此也没有this,与之相关的一切

也没有.
  - 打破封装,必须有一个类的内部声明,可访问任何成员通过 对象.来访

问.

* 静态
  - 是成员
  - 大家共用一份成员,整个类共用的成员.
- 静态数据成员: 在外部初始化
- 静态函数只能访问静态成员,类名::成员
====================================================
* 运算符重载(c++特有功能)
* 内部类
* 异常

拷贝构造函数除了名字特殊外毫无特殊之处.如下
A(const A& obj){
	cout << "我是拷贝构造函数" << endl;
}
A a = obj// 与 A a(obj)是等价的


#include <iostream>
using namespace std;

class A {
        int data;
public :
        A():data(5){ //初始化列表初始化的是成员而不是形参
                cout << "A()" << endl;
        }
        A(int d):data(d){
                cout << "A(int)" << endl;
        }
        A(bool b):data(b?123:234){
                cout << "A(bool)" << endl;
        }
        A(char c) : data((int)c){
                cout << "A(char)" << endl;
        }
        A(const A& o) : data(o.data){
                cout << "A(const A&)" << endl;
        }
        void show(){
                cout << "data=" << data << endl;
        }
        virtual ~A(){
                cout << "~A()" << endl;
        }
};
int main()
{
        A a1;//调用无参构造函数
        A a2(28);
        A a3(true);
        A a4('S');
        A a5(a2);
}
	
//用引用的好处
#include <iostream>
using namespace std;

class A {
        int data;
public :
        A():data(5){ //初始化列表初始化的是成员而不是形参
                cout << "A()" << endl;
        }
        A(int d):data(d){
                cout << "A(int)" << endl;
        }
        A(bool b):data(b?123:234){
                cout << "A(bool)" << endl;
        }
        A(char c) : data((int)c){
                cout << "A(char)" << endl;
        }
        //A(const A& o) : data(o.data){
        //       cout << "A(const A&)" << endl;
        //}
	//形参是一个新变量,在调用时创建,由实参来初始化.
	A(A o) : data(o.data){  //这样写是错误的,进入死循环
                cout << "A(const A&)" << endl;
        }
//创建对象时要调构造函数,调构造函数创建形参,形参又是一个新对象,
//创建新对象又要调构造函数,调构造函数又要创建形参,.......
        void show() const{
                cout << "data=" << data << endl;
        }
        virtual ~A(){
                cout << "~A()" << endl;
        //      show(200);
//      show(false);
//      show('A');
        //A a2(28);
        //A a3(true);
        //A a4('S');
        //A a5(a2);
        }
};
void show( A obj)
{
        obj.show();
}
void func( const A& obj)
{
        obj.show();
}
int main()
{
        A a1;//调用无参构造函数
        show(a1);
        func(a1);
}



当类无构造函数时,会自动产生A(),A(const A&)构造函数.

+ 当类成员有指针成员指向动态内存时默认拷贝构造函数会出问题.
   因为它会使两个指针指向同一个地方导致混乱.
   这时我们需要重写这个拷贝构造函数.如下示例:
#include <iostream>
using namespace std;

class A {
        int data;
public :
        A():data(5){ //初始化列表初始化的是成员而不是形参
                cout << "A()" << endl;
        }
	//拷贝构造函数
        A(const A& o)/* :data(o.data) */ {
                cout << "A(const A&)" << endl;
        }
        void show(){
                cout << "data=" << data << endl;
        }
        virtual ~A(){
                cout << "~A()" << endl;
        }
};
int main()
{
        A a1;
	a1.show(); //输出正常
	A a2(a1);
	a2.show(); //输出垃圾数据,所以初始化不能少
}  

在类的成员函数中可以访问本类中任何成员变量.

自已定义拷贝构造函数之后,就没有默认的拷贝构造函数了,要在

自己定义的拷贝构造函数中处理所有需要处理的数据.                 

                                                     
//动态数组类,长度可动态变化.未完整版
#include <iostream>
using namespace std;

class Array {
        char * p;
        int len;
public :
        Array(int n ) : len(n),p(NULL){
                resize(n);
        }
        Array( const Array& o ) : len(o.len) {
                p = new char[len];
                for( int i=0; i<len; i++ )
                        p[i] = o.p[i];
        }
        void resize( int n ){
                char * q = new char[n];
                int min = (n<len?n:len);
                if(p!=NULL){
                        for( int i=0; i<min; i++)
                                q[i] = p[i];
                        delete[] p;
                }
                p = q;
                for( int i=min; i<n; i++)
                        p[i] = '\0';
                len = n;
        }
        int size(){
                return len;
        }
        void set( int index, char c ){
                if( index<0 || index>len ){
                        cout << "Error" << endl;
                        return;
                }
                p[index] = c;
        }
        char get( int index ){
                if( index<0 || index>len ){
                        cout << "Error" << endl;
                        return '^';
                }
                return p[index];
        }
        void fill ( char start, int skip ){
                for( int i=0; i<len; i++)
                        p[i] = start + i*skip;
        }
        void show(){
                for( int i=0; i<len; i++){
                        cout << p[i];
                }
        }
        ~Array(){
                if(p!=NULL){
                        delete[ ] p;
                        p = NULL;
                }
        }
};  //end class Array 

int main()
{
        Array a1(10);
        a1.fill('a',2);
        a1.show();
        cout << endl;
        Array a2(a1);
        a2.fill('A',2);
        a2.show();
        cout << endl;
        a1.show();
        cout << endl;
        cout << "------------------" << endl;
        cout << "Please input text(end by '$') : " << endl;
        for(int i=0;;i++){
                char c;
                cin >> c;
                if(c=='$')
                        break;
                else if(i+1>a1.size()){
                        a1.resize(a1.size()+10);
                }
                        a1.set(i,c);
        }
        a1.show();
        cout << endl;
        for( int i=0; i<a1.size(); i++){
                cout << a1.get(i);
        }
}

========================================

默认的拷贝构造函数是浅拷贝,自己写的拷贝构造函数是深拷贝.

* 运算符函数
* 单目运算符

A operator+(A obj1,Aobj2){/* code */};

A a1(30),a2(50);
A result;
result = a1 + a2; //会去调A operator+(A obj1,Aobj2)
result.show();

//示例
//由程序可知成员比友员要方便,少传一个参数
#include <iostream>
using namespace std;
class A{
	//code
	A sub( const A& o){
		return A(data-o.data);
	}
	A oprator-()/......
};
A operator-(const A& o1, const A& o2){

	//code...
}
int main()
{
	A obj1(40),obj2(50);
	A obj3,obj4;
	obj3 = obj1.sub(obj2);
	obj3.show();
	obj4 = obj1 - obj2; //会去调obj1.aperator-(..)
}


运算符重载就是自已写运算符函数来规定运算符如何工作.

--------------------------
运算符函数的实现方法:
* 友元运算符函数:
  - 在类中声明friend
  - 定义:返回类型 operatorX(形参1,形参2)
  - 调用: obj1 X obj2 解释成 operatorX(obj1,obj2),返回值作为运

算结果
* 成员函数: 直接在类中定义
  - 定义: 返回类型 operatorX(形参1)
  - 调用: obj1 X obj2 解释成 obj1.operator(obj2),返回值作为运算

结果

cout << f1 << f2;//用重载运算符表示,只能通过友员来实现
// 如果要用成员函数,则会有cout.operator<<(const F& f),所以这是不

// 可能的.因此只能用友员来实现,operator<<(cout,f)
// 而cout是ostream型的,因此有以下标准格式.注意不能加const,因为//

cout是要改变的,会改变里的缓冲成员.
ostream& operator<<( /* 不能加const */ ostream& cout, const

F&)  //输出运算符的标准重载格式.
friend istream& operator>>(istream& is, F& f){

}//输入运算符重载标准格式

//重载运算符完整例子
//双目运算符重载
#include <iostream>
using namespace std;
class F{
        int n;
        int d;
public :
        F(int n=0, int d=1):n(n),d(d){}
        friend ostream& operator<<(ostream& os, const F& f){
                os << '[' <<  f.n << '/' << f.d <<']';
                return os;
        }
        F operator*(const F& o) {
                return F(n*o.n,d*o.d);
        }
        friend F operator/(const F& f1,const F& f2){
                return F(f1.n*f2.d,f1.d*f2.n);
        }
        friend istream& operator>>(istream& is, F& f){
                char ch;
                is >> f.n >> ch >> f.d;
                return is;
        }
};

int main()
{
        F f1(3,5),f2(11,7),f;
        cout << f1 << '*' << f2 << '=' << f1*f2 << endl;
        cout << f1 << '/' << f2 << '=' << f1/f2 << endl;
        cout << "Input 2 fractions :";
        cin >> f1 >> f2;
        cout <<"f1=" << f1 << endl;
        cout << "f2=" << f2 << endl;
}


* 单目运算符重载
  -友元函数形式,返回类型 operatorX(形参)
使用:X obj ---> operatorX(obj);
  -成员函数形式 尽量用成员  返回类型 operatorX(/*无形参*/)
使用: X obj ---> obj.operator();

//单目运算符重载
//把后++,后--当作双目运算符,第二个操作数是整形.
#include <iostream>
using namespace std;

class A{
        int data;
public :
        A(int d=0):data(d){}
        friend ostream& operator<<(ostream& os,const A& a){
        os << a.data;
        return os;
        }
        friend istream& operator>>(istream& is,A& a){
        is >> a.data;
        return is;
        }
        friend A& operator++(A& a){
                a.data += 10;
                return a;
        }
        A& operator--(){
                data -= 10;
                return *this;
        }
	//后加加,规定一个整形为形参,与先加加区分
        friend A/* 此时不再用引用 */ operator++(A& a,int){
                A old(a);
                a.data += 1;
                return old;
        }
	//后减减,规定为一个整形为形参,与先减减区分.
        A /*不要引用*/ operator--(int){
                A old(*this);
                data -= 1;
                return old;
        }
};

int main()
{
        A a1(50),a2(100);
        cout << "a1=" <<a1 << endl;
        cout << "a2=" <<a2 << endl;
        cout << "++a1=" << ++a1 << endl;
        cout << "--a1=" << --a1 << endl;
        cout << "a1++=" << a1++ << endl;
        cout << "a1=" <<a1 << endl;
        cout << "a2--=" << a2-- << endl;
        cout << "a2=" <<a2 << endl;

}


   运算符重载提供了一个自己规定运算符式作方式的方法,至少有一个操

作数是自定义类型的.基本类型我们是规定不了的.
   强制类型转换:类型(数据) --> (不必写返回类型,因为始终与后面的类

型是相同的) operator类型(无形参) 只能写成成员函数,不能是友员.

#include<iostream>
using namespace std;

class A{
	int data;
public:
	A(int d=0):data(d){}
	operator int(){
		return data;
	}
	operator bool(){
		return data!=0;
	}
	operator char(){
		return (char)data;
	}
};
int main()
{
	A a1(65),a2(200);
	cout << "a1=" << (char)a1 << endl;
	int d=a2;
	if(a2)
		cout << "good" << endl;
}

对自定义类型的对象,使用运算符时,总是调用相应的运算符函数

三目运算符不能重载.
等号是双目运算符也可重载,它也只能是成员.
还有点号('.')不能重载.
双冒号(::)不能重载.
sizeof(类型)没法重载.
#号不是运算符,无所谓重载.
'= () [] -> 类型转换'只能是成员函数来重载,其它的随便,我们建议尽量

使用成员函数来写,有点只能用友元,比如输入输出.
==================================================
+ 双目运算符重载
  - 友元形式:返  operator符号(形1,形2)
  - 成员形式:返 operator符号(形)
+ 单目运算符重载
  - 友元: 返  operator符号(形参)
  - 成员: 返 operator符号()
+ 特例
  - 加加
- 先加加
- 后加加 返回 operator符号(形,int)
  - 减减
- 先减减
- 后减减
  - 类型转换 只能是成员perator 空格 类型();
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics