精华内容
下载资源
问答
  • 大家知道,在C#类中一个最为特殊的方法——构造函数,它没有返回值且方法名称与类名相同。任何时候只要创建类,就会调用类的构造函数。同样,构造函数支持方法重载——这样就为类的使用者提供了多条实例化类的...

        大家都知道,在C#类中有一个最为特殊的方法——构造函数,它没有返回值且方法名称与类名相同。任何时候只要创建类,就会调用类的构造函数。同样,构造函数支持方法重载——这样就为类的使用者提供了多条实例化类的对象的途径。上述的这些观点相信大家都能理解,但构造函数的其他的一些特点你有所了解吗?本文将深入讲解构造函数。

    默认构造函数

        在默认情况下(也就是在类的定义中并没有明确写出构造函数的实现)C#将创建一个构造函数,该构造函数自动实例化对象,将对象的成员变量设置为其成员变量类型的默认值,C#中各类数据类型的默认值见下表:

    数据类型

    默认值

    bool false
    byte 0
    char ‘’
    decimal 0.0M
    double 0.0M
    enum 枚举值组合的第一个值
    float 0.0F
    int 0
    long 0L
    sbyte 0
    short 0
    struct 将所有的值类型字段设置为默认值,将所有的引用类型字段设置为null时产生的值
    uint 0
    ulong 0
    ushort 0

        如果我们在类的定义中明确的写出了带参数的构造函数,如下面的代码:

       1: public class Student
    
       2: {
    
       3:     private string name;    
    
       4:     public string Name
    
       5:     {
    
       6:         get { return this.name; }
    
       7:         set { this.name = value; }
    
       8:     }
    
       9: 
      10:     private int age;    
    
      11:     public int Age
    
      12:     {
    
      13:         get { return this.age; }
    
      14:         set { this.age = value; }
    
      15:     }
    
      16: 
      17:     public Student(string name, int age)
    
      18:     {
    
      19:         this.name = name;
    
      20:         this.age  = age;
    
      21:     }
    
      22: }
    

        在使用上面定义的Student类时,如下的代码编译将失败,编译器提示“‘Student’方法没有采用‘0’个参数的重载”:

       1: class Program
    
       2: {
    
       3:     static void Main()
    
       4:     {
    
       5:         Student stu = new Student();
    
       6:     }
    
       7: }
    

         为了能够使上面这段使用Student类的代码编译通过,我们需要在上面的Student类定义代码中添加一句“废话”:

       1: public Student() {}
    

        这是关于默认构造函数我们需要注意的地方。

    构造函数在类内部的调用

        构造函数在实例化类的对象是通过new关键字来调用,这个大家都知道。但在类的内部,我们怎么直接调用其构造函数呢?我们只能通过this关键字来调用,并且我们只能在构造函数的方法声明中调用类的另外一个构造函数,样例代码如下:

       1: public class Student
    
       2: {
    
       3:     private string name;
    
       4:     public string Name
    
       5:     {
    
       6:         get { return this.name; }
    
       7:         set { this.name = value; }
    
       8:     }
    
       9: 
      10:     private int age;
    
      11:     public int Age
    
      12:     {
    
      13:         get { return this.age; }
    
      14:         set { this.age = value; }
    
      15:     }
    
      16: 
      17:     private string grade;
    
      18:     public string Grade
    
      19:     {
    
      20:         get { return this.grade; }
    
      21:         set { this.grade = value; }
    
      22:     }
    
      23: 
      24:     public Student() 
    
      25:     {
    
      26:         Console.WriteLine("一个学生对象被实例化");
    
      27:     }
    
      28: 
      29:     public Student(string name, int age)
    
      30:         : this()
    
      31:     {
    
      32:         this
    
    展开全文
  • 网上说,是因为只有返回值,而中间不会抛出任何东西,或者是函数式编程不受任何外界的影响。 这一点我完全没有办法理解, 程序结构写完之后是固定的,当我输入什么,就输出什么,既然结构固定了,怎么还会影响...
  • 任何问题可以通过增加一个间接层来解决。 既然无法让一个阶乘函数反复调用自身,那就让 <code>factory</code> 在需要时反复生产出虽然不是同一个,但效果等价的、新的阶乘函数。我们设想以下特征的...
  • 任何使用yield语句的函数(在def中yield关键字)称为生成器。调用生成器函数将返回一个生成器。 2、生成器函数可以用return返回吗: 不可以,生成器函数返回值默认为生成器,return None也不可以,可以用空...

    一、关于生成器(generator)

    1、什么是生成器:

    任何使用yield语句的函数(在def中有yield关键字)都称为生成器。调用生成器函数将返回一个生成器。生成器对象是特殊的迭代器,具有迭代器一切的特点。

    2、生成器函数可以用return返回吗:

    不可以,生成器函数的返回值默认为生成器,return None也不可以,可以用空的return语句结束,指定返回值的话需要抛出SyntaxError异常。

    try:
            print(demo_name, next(seq))
        except StopIteration:
            print("序列溢出")
        # end try
    

    3、如何创建生成器及序列函数:

    yield 表达式只能用于定义生成器函数中,在函数外使用 yield 会导致 SyntaxError: ‘yield’ outside function ,仔细以下代码学习并作为使用模板:

    代码应用自:

    # 定义生成序列函数方法一:
    def demo1(demo_name):
        seq = range(3)
        print(demo_name, type(seq), seq)
        for i in seq:
            print(demo_name, "for in", i)
    
    # 定义生成序列函数方法二:
    def demo2(demo_name):
        seq = (x*x for x in range(3))
        print(demo_name, type(seq), seq)
        for i in seq:
            print(demo_name, "for in", i)
    
    # 定义序列生成器:
    def demo3(demo_name):
        def sequence_generator(num):
            """
            带有 yield 的函数在 Python 中被称之为 generator(生成器)
            执行到yield时:
                返回yield后的值
                暂停并跳出当前函数
                下次再调用函数会继续执行
            :param num:
            :return:
            """
            for _i_ in range(num):
                yield 2 * _i_
        # end def
    
        seq = sequence_generator(3)
        print(demo_name, type(seq), seq)
        print(demo_name, next(seq))
        print(demo_name, next(seq))
        print(demo_name, next(seq))
        try:
            print(demo_name, next(seq))
        except StopIteration:
            print("序列溢出")
        # end try
    
        for i in sequence_generator(5):
            print(demo_name, "for in", i)
    
    #定义迭代器
    def demo4(demo_name):
        class SequenceGenerator:
            def __init__(self, n):
                self.index = 0
                self.num = n
    
            def __iter__(self):
                return self
    
            def __next__(self):
                if self.index <= self.num:
                    r = self.index
                    self.index += 1
                    return r * 2
                else:
                    raise StopIteration
        # end class
        for i in SequenceGenerator(3):
            print(demo_name, "for in", i)
    
    
    if __name__ == '__main__':
        demo1("demo1")
        print()
    
        demo2("demo2")
        print()
    
        demo3("demo3")
        print()
    
        demo4("demo4")
        print()
    

    二、关于迭代器(iterator):

    1、什么是迭代器:

    迭代器(iterator)必须至少要定义 iter() 和 next() 两个方法,通过 iter() 和 next() 函数调用。 iter() 生成一个迭代器, next() 每调用一次都会返回下一个值,如果已经到最后一个值了,那么再调用 next() 就会引起 StopIteration 异常

    2、next()函数:

    next(iterator[, default]) 是内置的函数,通过调用 next() 方法取得 iterator 的下一个元素,所有元素消耗完再调用就会引起 StopIteration 异常。如果提供了 default 参数,则当取完所有元素后,再调用 next 时会返回 default 值,而不是引起 StopIteration 异常

    3、iter()函数:

    iter(object[, sentinel]) 内置函数会返回一个迭代器。没有第2个参数时, object 必须支持迭代协议(iter() 方法) 或序列协议 (getitem() 方法),否则会引起 TypeError 异常。如果有哨兵 (sentinel)参数, object 必须是可调用的对象,这种方式创建的迭代器每次调用 next() 方法时会以无参的形式调用 object ,如果返回值等于哨兵就会引起 StopIteration 异常,否则就返回这个值。

    4、如何定义迭代器:

    代码及定义参考以下链接

    #python的迭代器类需要实现__iter__魔法方法返回迭代器实例,还需要实现一个next方法,在迭代到末尾时抛出StopIteration异常表示迭代结束。如下简单示例:
    class SimpleIterator:
        def __init__(self, maxvalue):
            self.current = 0
            self.max = maxvalue
     
        def next(self):
            result = self.current
            self.current += 1
            if result == self.max:
                raise StopIteration()
            return result
     
        def __iter__(self):
            return self
     
     
    li = list(SimpleIterator(5))
    print li
     
    ################################
     
    class Reverse:
        """Iterator for looping over a sequence backwards."""
        def __init__(self, data):
            self.data = data
            self.index = len(data)
        def __iter__(self):
            return self
        def __next__(self):
            if self.index == 0:
                raise StopIteration
            self.index = self.index - 1
            return self.data[self.index]
    

    关于迭代器、容器、生成器可深入学习此链接内容

    展开全文
  • C++入门(三)

    2021-06-12 19:40:55
    构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员 都有 一个合适的初始值,并且在对象的生命周期内只调用一次。 构造函数特性: 其特征如下: 1. 函数名与类名...

    C++入门(三)

    1.类的6个默认成员函数(重点)

    如果一个类中什么成员都没有,简称为空类。

    空类中什么都没有吗?并不是的,任何一个类在我们不写的情 况下,都会自动生成下面6个默认成员函数。

     

    1.1.构造函数

    构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员 都有 一个合适的初始值,并且在对象的生命周期内只调用一次。

    构造函数特性:

    其特征如下:

    1. 函数名与类名相同。

    2. 无返回值。

    3. 对象实例化时编译器自动调用对应的构造函数。

    4. 构造函数可以重载

     

    class A
    {
    private:
    	int _a;
    	int _b;
    public:
    	A()//类A的无参构造函数
    	{
    		_a = 10;
    		_b = 11;
    	}
    
    	A(int a, int b)//带有参数的构造函数
    	{
    		_a = a;
    		_b = b;
    	}
    
    	void Print(void)
    	{
    		cout << _a << endl;
    		cout << _b << endl;
    	}
    };
    
    int main(void)
    {
    	A a1;//创建了一个类对象b1
    	//注意 不能想着调用的是无参构造函数就写成这样  A a1();这样是错误的
       //这样这个 A a1()就成立一个a1函数的声明了 也就是a1变成函数名了
       //该函数返回值类型是类类型  该函数函数名是a1  该函数无形参
    	a1.Print();//输出10 11 
    
    	A a2(15, 16);
    	a2.Print();//输出15 16
    
    	return 0;
    }

    可以看到

    A(int a, int b)//带有参数的构造函数

    A()//类A的无参构造函数

    是重载函数

     

    构造函数是特殊的成员函数,需要注意的是,构造函数的虽然名称叫构造,但是需要注意的是构造函数的主要任务并不是开空间创建对象,而是初始化对象

    怎么去理解构造函数的主要任务并不是开空间创建对象,而是初始化对象这句话呢 我们看下面这个代码

     

    class A
    {
    private:
    	int _a;
    	int _b;
    public:
    	A()//类A的无参构造函数
    	{
    		_a = 10;
    		_b = 11;
    	}
    
    	void Print(void)
    	{
    		cout << _a << endl;
    		cout << _b << endl;
    	}
    };
    
    int main(void)
    {
    	A a1;//创建了一个类对象b1
    	a1.Print();//输出10 11 
    
    	return 0;
    }

    我们创建了一个类对象a1 在类A中有一个无参的构造函数 我们要知道,构造函数的目的,不是创建这个对象a1 也不是给这个对象a1分配空间,仅仅是做到了一个初始化的作用

     

    1.11:构造函数的特点1

    如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成

     

    class Data
    {
    public:
    	void PrintInfo(void)
    	{
    		cout << this->_year << "年" << this->_month << "月" << this->_day << "日" << endl;
    	}
    
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    int main(void)
    {
    	Data d1;
    	d1.PrintInfo();//输出结果:-858993460年-858993460月-858993460日
    
    	return 0;
    }

    在Data类中,我们没有定义无参或者有参构造函数,根据特点 C++编译器会自动生成一个无参的默认构造函数并且去调用,我们在反汇编中可以看到如下

    但是我们看输出结果,一定很奇怪,这个自动生成的构造函数怎么没有对我们对象中的变量进行初始化 我们再来看下面的代码

    class Time
    {
    public:
    	Time()
    	{
    		_hour = 1;
    		_mintue = 2;
    		_second = 3;
    	}
    private:
    	int _hour;
    	int _mintue;
    	int _second;
    };
    
    class Data
    {
    public:
    	void PrintInfo(void)
    	{
    		cout << _year << "年" << _month << "月" << _day << "日" << endl;
    	}
    
    private:
    	int _year;
    	int _month;
    	int _day;
    	Time _t;
    };
    
    int main(void)
    {
    	Data d1;
    	d1.PrintInfo();//输出结果:-858993460年-858993460月-858993460日
    
    	return 0;
    }

    我们多定义了Time类 在Time类中有一个无参的构造函数,然后在Data类中 我们增加了一个成员变量 Time _t 现在我们到VS监视中看一下

    可以看到,在d1中,对于成员变量year、month、day还是一个随机值 但是对于 hour、mintue、second都已经通过调用Time类中的无参构造函数对其进行了初始化。为什么会产生这样的原因

    这是因为C++有这样一个特性

    1:针对内置类型的成员变量没有做处理(内置类型也就是int char double float等类型)

    2:针对自定义类型的成员变量(自定义类型就是我们使用class/struct/union自己定义的类型),调用它的构造函数初始化(如果自定义的成员变量所处的自身类中也没有构造函数,那么也是随机值)

    总结:编译器自动生成的构造函数,在存在自定类型的时候,是有作用的(也就是去调用自定义类型的构造函数),但是对于只存在内置类型的时候,自动生成的构造函数不能说没有作用,只能是没有意义的,

    那什么叫一旦用户显式定义编译器将不再生成自动生成的构造函数呢

     

    class A
    {
    private:
    	int _a;
    	int _b;
    public:
    	A(int a, int b)//我们定义了类A的无参构造函数
    	{
    		_a = a;
    		_b = b;
    	}
    	void Print(void)
    	{
    		cout << _a << endl;
    		cout << _b << endl;
    	}
    };
    
    int main(void)
    {
    	A a1(12, 13);//创建了一个类对象b1
    	a1.Print();//输出12 13
       //A a2;这样会报错 因为编译器觉得,你连有参的构造参数都会定义
       //那么无参的肯定也会 但是编译器找不到 就会报错,编译器不会再去自动生成无参的
    
    	return 0;
    }

    如上,我们自己定义了一个类A的无参构造函数,那么编译器就不会自动生成了,而是按照我们定义的去执行,如同a1一样,那么像a2这种,我们只是定义了一个有参的构造函数,但是并没有定义无参的,那么编译器也是不会去生成无参构造函数的,而是觉得,你连有参的都会自己定义,那么无参的你也会,但是编译器并没有找到,所以会报错

     

    1.12:构造函数的特点2

    无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参 构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数。

    首先我们要知道一点:什么是默认构造函数,我们这么理解 也就是不需要传参数的

    你看 ,无参构造函数,全缺省构造函数是不是都不需要传递参数 是吧

     

    class A
    {
    private:
    	int _a;
    	int _b;
    public:
    	A()//自定义的无参构造函数
    	{
    		_a = 10;
    		_b = 20;
    	}
    	A(int a, int b)//自定义的带参构造函数
    	{
    		_a = a;
    		_b = b;
    	}
    	void Print(void)
    	{
    		cout << _a << endl;
    		cout << _a << endl;
    	}
    };
    
    class A
    {
    private:
    	int _a;
    	int _b;
    public:
    	A(int a = 12, int b = 13)//自定义的带参全缺省构造函数
    	{
    		_a = a;
    		_b = b;
    	}
    	void Print(void)
    	{
    		cout << _a << endl;
    		cout << _a << endl;
    	}
    };

    我们来看一下两个类A 在第一个类A中 我们定义了一个无参构造函数和一个带两个参数的有参构造函数 在第二个类A中 我们定义了一个全缺省的构造函数,却也是可以达到第一个类A中的效果

    甚至说 如果在主函数中 针对第一个类 定义了一个这样的对象 A a1(12) 只带一个参数的情况下会报错,因为找不到只带一个参数的构造函数

    但是有一点需要注意,在第二个类中,不能存在如下情况:

     

    class A
    {
    private:
    	int _a;
    	int _b;
    public:
        A()//自定义无参构造函数
        {
            _a = 10;
            _b = 11;
        }
    	A(int a = 12, int b = 13)//自定义的带参全缺省构造函数
    	{
    		_a = a;
    		_b = b;
    	}
    	void Print(void)
    	{
    		cout << _a << endl;
    		cout << _a << endl;
    	}
    };
    
    int main (void)
    {
        A a1;//不知道要调用哪个
    }

    这样是不行的,我们在类A中有一个无参构造函数和一个全缺省的构造函数,这样是错误的,因为这样就相当于有了两个默认构造函数,试想一下 你在主函数中生成了一个对象a1 编译器都不知道要调用哪一个 这样就矛盾了

     

    1.2.析构函数

    析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。

    而对象的生命周期到的时候,在销毁时会自动调用析构函数,完成类的一些资源清理工作(malloc开辟的空间,打开文件等等)

    class A
    {
    private:
    	int _a;
    public:
    	A()//默认构造函数
    	{
    		_a = 10;
    	}
    	~A()//析构函数
    	{
    		cout << "我是完成清理工作" << endl;
    	}
    };
    
    int main(void)
    {
    	A a1;
    }

     

    如上所示,程序运行之后,终端是输出了一个"我是完成清理工作" 说明程序进入到过析构函数中,

    但是有一点要注意 a1这个局部对象并不是析构函数来销毁的,因为是局部对象,所以存放在栈上,所以在生命周期到了之后 由程序自己释放。析构函数的作用仅仅是垃圾清理。

    打个比方:就好像餐厅收拾桌子的服务员,他的任务仅仅是把桌上的垃圾收拾到垃圾桶中,但是这些垃圾真正的处理是垃圾处理厂,却不是他们一样的道理

    析构函数特性

    析构函数是特殊的成员函数。

    其特征如下:

    1. 析构函数名是在类名前加上字符 ~。

    2. 无参数无返回值。(注意 这里不仅仅是返回值没有 形参也不能有)

    3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。

    4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

     

    1.21:析构函数的特点1

     

    class Stack
    {
    public:
    	Stack()
    	{
    		cout << "我构造的对象的空间地址" << this << endl;
    		_a = (int*)malloc(sizeof(int) * 10);
    		pTop = 0;
    		campity = 0;
    	}
    
    	~Stack()
    	{
    		if (_a)
    		{
    			cout << "我清理的对象的空间地址" << this << endl;
    			free(_a);
    			_a = nullptr;
    			pTop = campity = 0;
    		}
    	}
    private:
    	int* _a;//栈空间
    	int pTop;//栈顶
    	int campity;//栈空间大小
    };
    
    
    int main(void)
    {
    	Stack s1;//对象s1
    	Stack s2;//对象s2
    
    	return 0;
    }

    如上代码所示,我们定义了一个Stack类,并且在无参构造函数中为其开辟了一个40字节大小的空间,而析构函数所做的事情,正是处理这个动态开辟的空间的资源。

    同时 很重要的一点,析构函数的调用顺序是和构造函数相反的

    如在主函数中我们定义了对象s1、s2,因为是局部变量,要满足栈的特定先入后出,

    所以我们先入栈s1、在入栈s2,但是调用析构的函数的时候,我们是先调用s2的析构函数,再调用s1的析构函数

     

    1.22:析构函数的特点2

    编译器自动生成的析构函数

     

    class Time
    {
    public:
    	Time()//time中的默认构造函数
    	{
    		_hour = 1;
    		_mintue = 2;
    		_second = 3;
    	}
        ~Time()//time中我们自定义的析构函数
    	{
            cout<<"资源清理"<<endl;
        }
    private:
    	int _hour;
    	int _mintue;
    	int _second;
    };
    
    class Data
    {
    public:
    	void PrintInfo(void)
    	{
    		cout << _year << "年" << _month << "月" << _day << "日" << endl;
    	}
        Data()
        {
            _year = 1996;
            _month = 12;
            _day = 16;
        }
    private:
    	int _year;
    	int _month;
    	int _day;
    	Time _t;
    };
    
    int main(void)
    {
    	Data d1;
    
    	return 0;
    }

    如上述代码所示,我们在类Time中自定义了析构函数,但是在Data类中没有生成析构函数,编译之后我们发现,在反汇编中,Data类调用了自动生成的析构函数

    并且在终端上打印了"资源清理" 说明函数进入到了Time类调用了Time类中的析构函数

    也就是说 先进入Data类中的析构函数,在Data类中的析构函数存在了Time类的析构函数,然后调用Time类的析构函数,然后调用结束 也就是如下

    ~Data()//系统自动生成的析构函数
        {
            ~Time();//会去调用Time类的析构函数
        }

    1.23:析构函数的特点3

     

    class Time
    {
    public:
    	Time()//time中的默认构造函数
    	{
    		_hour = 1;
    		_mintue = 2;
    		_second = 3;
    	}
        ~Time()//time中我们自定义的析构函数
    	{
            cout<<"资源清理"<<endl;
        }
    private:
    	int _hour;
    	int _mintue;
    	int _second;
    };
    
    class Data
    {
    public:
        Data()
        {
            _year = 1996;
            _month = 12;
            _day = 16;
        }
        ~Data()
        {
        }
        //我们自己生成了一个析构函数,但是里面什么都没做
        //也没有调用Time类中的析构函数
    private:
    	int _year;
    	int _month;
    	int _day;
    	Time _t;
    };
    
    int main(void)
    {
    	Data d1;
    
    	return 0;
    }

    在代码调试的过程中,我们发现,虽然我们自己在Data类中的自己定义的析构函数什么都没做,但是仍然会去调用Time类的析构函数

    总结:对于编译器自动生成的析构函数,我们可以理解成编译器自动生成的构造函数一个结论

    1:针对内置类型的成员变量没有做处理(内置类型也就是int char double float等类型)

    2:针对自定义类型的成员变量(自定义类型就是我们使用class/struct/union自己定义的类型),调用它的析构函数

    总结:编译器自动生成的析构函数,在存在自定类型的时候,是有作用的(也就是去调用自定义类型的构造函数),其实正常情况下,

    如果类中没有申请资源,我们是不需要自己去定义析构函数的,但是对于有申请资源的,我们需要去定义析构函数,对资源进行释放。

    1.3 拷贝构造函数

    构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用

     

    class A
    {
    private:
    	int _a;
    	int _b;
    public:
    	A(int a = 1, int b = 5)
    	{
    		_a = a;
    		_b = b;
    	}
    
    	A(const A& aa)//拷贝构造函数
    	{
    		_a = aa._a;
    		_b = aa._b;
    	}
    
    	void Print(void)
    	{
    		cout << _a << "\t" << _b << endl;
    	}
    
    	~A()
    	{
    
    	}
    };
    
    int main(void)
    {
    	A a1(12, 13);
    	a1.Print();//输出12 13
    
    	A a2(a1);//调用了拷贝构造函数
    	a2.Print();//输出12 13
    
    	return 0;
    }

    特征:

    拷贝构造函数也是特殊的成员函数,

    其特征如下:

    1. 拷贝构造函数是构造函数的一个重载形式。

    2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。

     

    class A
    {
    private:
    	int _a;
    	int _b;
    public:
    	A(int a = 1, int b = 5)
    	{
    		_a = a;
    		_b = b;
    	}
    	A(A aa)//假如拷贝构造函数是传值方式
    	{
    		_a = aa._a;
    		_b = aa._b;
    	}
    
    	void Print(void)
    	{
    		cout << _a << "\t" << _b << endl;
    	}
    
    	~A()
    	{
    
    	}
    };
    
    int main(void)
    {
    	A a1(12, 13);
    	a1.Print();//输出12 13
    
    	A a2(a1);//报错
    
    	return 0;
    }

    为什么使用传值的方式会发生无穷递归调用从而编译器报错呢,我们这么看

    什么意思呢 就是我们在主函数中 有这么一句 A a2(a1) 那么这个时候,就会去调用拷贝构造函数A(A aa)

    然后就要把a1传递给aa 但是对于这种自定义类型 把a1传递给aa 这个过程 就相当于aa(a1) 然后又要去调用拷贝构造函数 A (A aa) 这样就会变成无限循环递归了。

    所以我们使用引用的方式 同时把const加上 这样可以保证作为实参引用的形参不会修改实参的值

    同时,要注意一点,拷贝构造函数 只是把a1对象中的值 拷贝给a2对象中,而不是a1和a2都指向同一块空间。下面可以看到 两者的地址是不同的

     

    1.31:拷贝构造特点1

     

    class A
    {
    private:
    	int _a;
    	int _b;
    public:
    	A(int a = 1, int b = 5)
    	{
    		_a = a;
    		_b = b;
    	}
    //加上一个断点
    	A(const A& aa)//拷贝构造函数
    	{
    		_a = aa._a;
    		_b = aa._b;
    	}
    
    
    	void Print(void)
    	{
    		cout << _a << "\t" << _b << endl;
    	}
    
    	~A()
    	{
    
    	}
    };
    //加一个断点
    void fun1(A bb)//传值的方式
    {
    
    }
    
    int main(void)
    {
    	A a1(12, 13);
    	fun1(a1);
    
    	return 0;
    }

    当我们使用vs编译器进行调试的时候,会发现,我们运行到fun1函数的时候,不是直接进入函数体,而是会先去调用拷贝构造函数,调用结束之后 在进入fun1函数的函数体。

    为什么呢,因为对于fun1函数,我们把a1传递给fun1中的形参bb 相当于bb = a1,所以我们调用拷贝构造函数,然后在执行fun1

     

    1.32:拷贝构造特点2(重点)

    拷贝构造函数若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,或者值拷贝

     

    如上两个代码,同样在类中都没有定义拷贝构造函数,所以系统会自动生成,但是发现,在执行代码2的时候,程序奔溃了,奔溃的地点在代码2析构函数中的free(_str) 为什么呢

    通过编译器的监视功能,我们看到,代码1是正常的 把a1中的值,通过系统生成的拷贝构造函数赋值给了a2

    但是我们通过编译器的监视功能看代码2的时候,发现了一个特殊的一点,虽然两个对象s1、s2是不同的,但是两个对象中的_str指向的空间确实一样的。

    这样大概也就发现了奔溃的原因,在把s1通过拷贝构造函数拷贝给s2的时候,直接把里面字符串的首地址空间复制给了s2中的_str 然后析构函数先释放s2中的空间,

    也就是s2中的_str中的动态空间已经被s2的析构函数释放并且置空了,这个时候,再去调用s1对象的析构函数,就会奔溃,因为空间没了,

    但是s1中的_str的指向却还是那个被释放的空间首地址,这个时候,s1中的_str就是野指针了所以奔溃了。

     

    改动:在代码2中加上我们自定义的拷贝构造函数

    String(const String& s)//代码2用户自定义拷贝构造函数
    	{
    		strcpy(_str, s._str);
    	}

     

    总结:

    如果一个类中未涉及到资源管理时,拷贝构造函数是否用户写出都可以

    如果一个类中涉及到资源管理时,拷贝构造函数必须要用户写出

    否则编译器生成的默认的拷贝构造函数可能会出问题

    什么是涉及到资源管理,也就是在类中有没有(动态开辟空间,打开文件等)

     

    1.33:拷贝构造特点3(重点)

    class A
    {
    private:
    	int _a;
    	int _b;
    public:
    	A(int a = 1, int b = 5)
    	{
    		_a = a;
    		_b = b;
    	}
    	A(const A& aa)
    	{
    		_a = aa._a;
    		_b = aa._b;
    	}
    };
    
    int main(void)
    {
    	A a1(12, 13);
    	A a2(13, 14);
    	a2(a1);
    
    	return 0;
    }

    如上代码,发现程序报了一下如下的错误

    这也是我们经常忽略的一点,要注意,拷贝构造函数并不是一个单纯的赋值函数,它是有先天条件的,即在用已存在的类类型对象创建新对象时由编译器自动调用,

    也就是说,在调用拷贝构造函数的同时必须生成一个新的对象,并且拷贝的对象要是已经已经存在的对象。

    但是如果换成这样 那么就可以

    int main(void)
    {
    	A a1(12, 13);
    	A a2 = a1;//调用拷贝构造  A a2(a1)两者等价
    	
    
    	return 0;
    }

    1.4 运算符重载

    C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

    函数名字为:关键字operator后面接需要重载的运算符符号。

    函数原型:返回值类型 operator操作符(参数列表) 参数的个数由运算符需要操作的参数决定,如果在类中定义,就要少定义一个参数(具体的情况示运算符决定)

    为什么需要运算符重载函数:因为有些自定义的类型是不能直接使用运算符的,所以我们需要使用到运算符重载

    示例:void operator+(const Data&a1, const Data&a2) 这个是对‘+’号运算符的重载

     

    class Data
    {
    public:
    	Data(int year = 2012, int month = 12, int day = 1)//默认构造函数
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    
    	Data(const Data& d)//拷贝构造函数
    	{
    		_year = d._year;
    		_month = d._month;
    		_day = d._day;
    	}
    
    	void Print(void)//输出函数
    	{
    		cout << _year << "年" << _month << "月" << _day << "日" << endl;
    	}
    
    	bool operator==(const Data& d2)
    	{
    		if (_year == d2._year && _month == d2._month && _day == d2._day)
    		{
    			cout << "两者日期相等" << endl;
    			return true;
    		}
    		else
    		{
    			cout << "两者日期不相等" << endl;
    			return false;
    		}
    	}
    
    	~Data()//Data类的析构函数
    	{
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    int main(void)
    {
    	Data d1;
    	Data d2(2021, 12, 1);
    
    	d1.Print();
    	d2.Print();
    
    	d1.operator==(d2);//输出结果  打印"两者日期不相等"  返回false
    
    	return 0;
    }

    注意:

    1:不能通过连接其他符号来创建新的操作符:比如operator@

    2:重载操作符必须有一个类类型或者枚举类型的操作数

     

    int operator+(int& a1, int& a2)//这样是错误且没有任何意义的
    {
    	return a1 + a2;
    }

    如上所示,重载了+号运算符,但是其形参都是两个整型,这样是错误,没有任何意义的,因为对于两个整型使用+号运算符,本来就是被允许的,并且已经由C和C++底层代码实现了

     

    3:用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义

    示例:把运算符'+' 重载成减法的内容 (禁忌!!!)

     

    4:作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的 操作符有一个默认的形参this,限定为第一个形参

     

    //类中定义==运算符重载函数
    class Data
    {
    public:
    	Data(int year = 2012, int month = 12, int day = 1)//默认构造函数
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    
    	Data(const Data& d)//拷贝构造函数
    	{
    		_year = d._year;
    		_month = d._month;
    		_day = d._day;
    	}
    	bool operator==(const Data& d2)
    	{
    		if (_year == d2._year && _month == d2._month && _day == d2._day)
    		{
    			cout << "两者日期相等" << endl;
    			return true;
    		}
    		else
    		{
    			cout << "两者日期不相等" << endl;
    			return false;
    		}
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    int main(void)
    {
    	Data d1;
    	Data d2(2021, 12, 1);
    	d1.operator==(d2);//输出结果  打印"两者日期不相等"  返回false
     
       //如果是类外对==进行重载
       d1 == d2;//那么这么写就会调用该重载了 等价于 operator==(d1,d2)
       
    
    	return 0;
    }
    //类外定义==运算符重载函数 有一个要求
    //必须把private成员定义成public的 不然会错误
    bool operator==(const Data& d1, const Data& d2)
    	{
    		if (d1._year== d2._year && d1._month == d2._month && d1._day == d2._day)
    		{
    			cout << "两者日期相等" << endl;
    			return true;
    		}
    		else
    		{
    			cout << "两者日期不相等" << endl;
    			return false;
    		}
    	}

    如上所示,在类中定义的重载函数,如果运算符的操作数是两个,那么我们要少定义一个形参,

    我们只要在主函数中 d1.operator==(d2) 这样写的意思是 我们需要比较d1对象和d2对象的值的大小,所以可以在类中少定义一个参数,因为有着this指针的存在。

    这个时候,类中的重载函数可以看成这样

    bool operator==(Data*cosnt this, const Data& d2)
    	{
    		if (this->_year == d2._year && this->_month == d2._month && this->_day == d2._day)
    		{
    			cout << "两者日期相等" << endl;
    			return true;
    		}
    		else
    		{
    			cout << "两者日期不相等" << endl;
    			return false;
    		}
    	}

    5:.* (这里是点和*一起, 不是单纯的*,*号是可以重载的)、:: (作用域运算符)、sizeof 、?: (三目运算符)、. (点)注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

     

    1.41:赋值运算符的重载(1)

    一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝。

     

     

    如上所示,也是两个代码,代码1和代码2都没有我们自己定义的赋值运算符的重载函数,我们发现了一点,跟拷贝构造函数很类似,代码1是正常执行的,但是代码2却奔溃了。为什么?

    通过看代码1的监视,发现代码1 没有问题,成功把a1中的值赋值给了a2

    但是查看代码2的监视发现,在执行赋值操作的时候,s1中_str的地址也随着s2中_str的复制改变了,所以奔溃的原因也是同拷贝构造函数一样,多次释放。

    总结:当类中存在资源管理的时候(打开文件,动态开辟空间),赋值运算符重载必须要用户定义出来

     

    1.42:赋值运算符的重载(2)

    复制运算符重载函数的注意点:1. 参数类型 2. 返回值 3. 检测是否自己给自己赋值 4. 返回*this

     

    class A
    {
    private:
    	int _a;
    	int _b;
    public:
    	A(int a = 1, int b = 5)
    	{
    		_a = a;
    		_b = b;
    	}
    	A(const A& aa)
    	{
    		_a = aa._a;
    		_b = aa._b;
    	}
    	A& operator=(const A& aa)//赋值运算符的重载函数
    	{
    		if (this != &aa)
    		{
    			_a = aa._a;
    			_b = aa._b;
    		}
    		return *this;
    	}
    };
    
    int main(void)
    {
    	A a1(12, 13);
    	A a2(13, 14);
    	a2 = a1;
    
    	return 0;
    }

    首先,我们来看一下我们自己定义的赋值运算符重载函数

    1:为什么形参要是const A& aa,而不能是 A aa,如果是A aa 编译器会先去调用拷贝构造函数,使用引用的话,可以少一层构造。其次,为什么要使用const修饰,使用const的目的主要还是怕用户在赋值运算符重载函数中对其进行了修改。

    2:为什么需要检测是否是给自己赋值:因为给自己赋值 没有意义 可以让程序少执行该步骤

    3:为什么返回的*this 而不能是aa 关于这个问题,我们拿整型数字举例看一看

        int i = 0, j = 1, k = 2;
        i = j = k;

    试想一下 i = j = k 这个过程是怎么完成的,应该是从右往左进行,拆解开来看 就是先 j = k 然后再 i = j,那么就可以知道,每一次的返回值就是被赋值的那个操作数,那么就是*this

    4:返回值是类类型的引用而不用类类型的原因是(考虑到部分涉及到了资源管理),因为返回的*this 如果返回值是类类型的话,那么在返回的时候,程序就会去调用一次拷贝构造函数,在调用拷贝构造函数,但是因为使用的类类型,那么这个时候的返回值就是一个局部的变量,在该函数结束的时候,变量指向的空间就被释放了,那么再返回回去,析构的时候,就奔溃了。所以直接使用类类型的引用,因为*this本来就是对象的地址,所以没问题。错误如下:

    附加:但是还要注意一点,如果存在动态资源管理,再进行赋值的时候,要考虑到两个对象空间的大小。尽量大一点,不然会出错

     

    1.5:一个日期类的完善

     

    //Data_Head.h头文件
    #pragma once
    # include <iostream>
    
    using namespace std;
    
    class Date
    {
    public:
    	int GetMonthDay(int year, int month)// 获取某年某月的天数
    	{
    		static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    		int day = days[month];
    		if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
    		{
    			day += 1;
    		}
    		return day;
    	}
    	bool operator>(const Date& d);// >运算符重载 ok
    	bool operator==(const Date& d);// ==运算符重载 ok
    	bool operator >= (const Date& d);// >=运算符重载 ok
    	bool operator < (const Date& d);// <运算符重载 ok
    	bool operator <= (const Date& d);// <=运算符重载 ok
    	bool operator != (const Date& d);//!= 运算符重载 ok
    
    	Date(int year = 1900, int month = 1, int day = 1);// 全缺省的构造函数 ok
    	Date(const Date& d);// 拷贝构造函数 ok
    	~Date();// 析构函数 ok
    	void Print(void);//输出当前日期
    
    	Date& operator+=(int day);// 日期+=天数 ok
    	Date operator+(int day);// 日期+天数ok
    	Date operator-(int day);// 日期-天数ok
    	Date& operator-=(int day);// 日期-=天数 ok
    
    	Date& operator++();// 前置++ ok
    	Date operator++(int);// 后置++ ok
    	Date operator--(int);// 后置-- ok
    	Date& operator--();// 前置-- ok
    
    	int operator-(const Date& d);// 日期-日期 返回天数 ok
    
    	Date& operator=(const Date& d);// 赋值运算符重载
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    //Data.cpp文件
    
    # include <iostream>
    
    # include "Data_Head.h"
    
    using namespace std;
    
    Date::Date(int year, int month, int day)// 全缺省的构造函数
    {
    	if (year >= 0 && (month >= 1 && month <= 12) && ((day >= 1) && (day <= GetMonthDay(year, month))))
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    	else
    	{
    		cout << "非法日期" << endl;
    	}
    	
    }
    
    Date::Date(const Date& d)// 拷贝构造函数
    {
    	_year = d._year;
    	_month = d._month;
    	_day = d._day;
    }
    
    Date::~Date()//析构函数
    {
    }
    
    bool Date::operator>(const Date& d)// >运算符重载
    {
    	if ((_year > d._year) || ((_year == d._year) && (_month > d._month)) || (((_year == d._year) && (_month == d._month)) && (_day > d._day)))
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    
    bool Date::operator < (const Date& d)// <运算符重载
    {
    	if ((_year < d._year) || ((_year == d._year) && (_month < d._month)) || (((_year == d._year) && (_month == d._month)) && (_day < d._day)))
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    
    bool Date::operator==(const Date& d)// ==运算符重载
    {
    	if (_year == d._year && _month == d._month && _day == d._day)
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    
    bool Date::operator != (const Date& d)//!= 运算符重载
    {
    	if (operator==(d))
    	{
    		return false;
    	}
    	else
    	{
    		return true;
    	}
    }
    
    bool Date::operator >= (const Date& d)// >=运算符重载
    {
    	if (operator>(d) || operator==(d))
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    
    bool Date::operator <= (const Date& d)// <=运算符重载
    {
    	if (operator<(d) || operator==(d))
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    
    Date& Date::operator+=(int day)// 日期+=天数
    {
    	_day = _day + day;
    	int TmpDay = GetMonthDay(_year, _month);
    	if (_day <= TmpDay)
    	{
    		return *this;
    	}
    	else
    	{
    		while (_day > TmpDay)
    		{
    			_month += 1;
    			if (_month > 12)
    			{
    				_month = 1;
    				_year += 1;
    			}
    			_day = _day - TmpDay;
    			TmpDay = GetMonthDay(_year, _month);
    		}
    		return *this;
    	}
    }
    
    Date& Date::operator-=(int day)// 日期-=天数
    {
    	int TmpDay = 0;
    	if (_day > day)
    	{
    		_day = _day - day;
    		return *this;
    	}
    	else if (_day == day)
    	{
    		_month -= 1;
    		if (_month == 0)
    		{
    			_year -= 1;
    			_month = 12;
    		}
    		_day = GetMonthDay(_year, _month);
    	}
    	else
    	{
    		_day = _day - day;
    		while (_day <= 0)
    		{
    			_month -= 1;
    			if (_month  == 0)
    			{
    				_year -= 1;
    				_month = 12;
    			}
    			TmpDay = GetMonthDay(_year, _month);
    			_day = _day + TmpDay;
    		}
    		return *this;
    	}
    }
    Date Date::operator+(int day)// 日期+天数
    {
    	Date d2(*this);
    	d2.operator+=(day);
    	return d2;
    }
    Date Date::operator-(int day)// 日期-天数
    {
    	Date d2(*this);
    	d2.operator-=(day);
    	return d2;
    }
    
    Date& Date::operator++()// 前置++
    {
    	operator+=(1);
    	return *this;
    }
    Date Date::operator++(int)// 后置++
    {
    	Date d2(*this);
    	operator+=(1);
    	return d2;
    }
    Date Date::operator--(int)// 后置--
    {
    	Date d2(*this);
    	operator-=(1);
    	return d2;
    }
    Date& Date::operator--()// 前置--
    {
    	operator-=(1);
    	return *this;
    }
    
    int Date::operator-(const Date& d)// 日期-日期 返回天数
    {
    	int sum = 0;
    	Date d1(*this);
    	if (d1.operator==(d))
    	{
    		return 0;
    	}
    	else
    	{
    		int i = 0;
    		if (d1.operator>(d))
    		{
    			while (d1.operator!=(d))
    			{
    				--d1;
    				++i;
    			}
    			return i;
    		}
    		else
    		{
    			while (d1.operator!=(d))
    			{
    				++d1;
    				++i;
    			}
    			return i;
    		}
    	}
    }
    
    Date& Date::operator=(const Date& d)// 赋值运算符重载
    {
    	if (this != &d)
    	{
    		_year = d._year;
    		_month = d._month;
    		_day = d._day;
    	}
    	return *this;
    }
    
    void Date::Print(void)//输出当前日期
    {
    	cout << _year << "年" << _month << "月" << _day << "日" << endl;
    }
    
    
    //The_Main.cpp文件
    # include <iostream>
    
    # include "Data_Head.h"
    
    using namespace std;
    
    int main(void)
    {
    	Date d1(2020, 1, 2);
    	d1.Print();//输出1900 1 1
    	Date d2(2020, 1, 1);
    	d2.Print();//输出1900 12 1
    
    	/*cout << (d1 == d2) << endl;
    	cout << (d1 != d2) << endl;
    	cout << (d1 <= d2) << endl;
    	cout << (d1 >= d2) << endl;
    	cout << (d1 < d2) << endl;
    	cout << (d1 > d2) << endl;*/
    
    	/*Date d3 = d1++;
    	d3.Print();
    	d1.Print();*/
    
    	int Tmpday = d1- d2;
    	cout << Tmpday << endl;
    
    
    
    
    	return 0;
    }

     

     

     

     

    展开全文
  • 可能你已经注意到,变量都有一个美元符号($)的前缀。所有变量都是局部变量,为了使得定义的函数中可以使用外部变量,使用global语句。而你要将该变量的作用范围限制在该函数之内,使用static语句。 $g_var = 1 ; /...
  •  Java Bean 是可复用的组件,对Java Bean并没有严格的规范,理论上讲,任何一个Java类可以是一个Bean。但通常情况下,由于Java Bean是被容器所创建(如Tomcat)的,所以Java Bean应具有一个无参的构造器,另外,...
  • 在Java或Python中,如果...但是,在特殊情况下,比如,任何结果都有可能是预期值,这时候,就无法通过返回值告知调用者函数出异常了。那么,这时候该怎么办?难道C遇到这种情况就无法处理了吗?非也,C有其特殊的方式,
    • JavaPython中,如果一个函数/方法,得不到预期结果,我们可以通过抛异常的方式通知调用者,程序并不能得到预期结果。

    • 但是在C中,无法通过这种方式告知调用者。一般情况下,我们可以通过返回一个不可能的值告知计算失败。但是,在特殊情况下,比如,任何结果都有可能是预期值,这时候,就无法通过返回值告知调用者函数出异常了。那么,这时候该怎么办?难道C遇到这种情况就无法处理了吗?非也,C有其特殊的方式,就是通过指针连变相返回结果。而函数返回值表示函数计算成功/失败。

    • 比如除法运算函数,当除数为0,就会计算失败。如果仅仅通过返回值,并不清楚得到的结果是正确的结果还是计算失败给出的返回值。于是,可以通过指针的方式来变相给出结果。而返回值作为计算成功还是失败的标志给出。

    #include <stdio.h>
    
    int main(void){
        int a =9;
        int b = 2;
        int c;
        int ret = divider(a,b,&c);
        if (ret){
            printf(" %d/%d = %d\n",a,b,c);
        }else{
            printf("%d/%d ==> 除数为0,无法计算",a,b);
        }
    
        return 0;
    }
    /**
    * @return 0 ,程序出错; 1, 程序正常
    */
    int divider(int a,int b,int *result){
        int ret;
        if(b==0){
            ret=0;
        }else{
            *result = a/b;
            ret = 1;
        }
        return ret;
    }
    

    console log:

    9/0 ==> 除数为0,无法计算
    9/2 = 4
    展开全文
  • java constructor

    千次阅读 2018-04-30 20:34:27
     可以的,但要有返回值,起码void也行,不然就成了构造函数。但是不建议这样做。在Java中,任何变量在被使用前必须先设置初值.Java提供了为类的成员变量赋初值的专门功能:构造方法(constructor)构造方法是一种特殊...
  • 2. 从内核里看进程和线程是一样的,都有各自不同的PCB,但是PCB中指向内存资源的三级页表是相同的 3. 进程可以蜕变成线程 4. 线程可看做寄存器和栈的集合 5. 在linux下,线程最是小的执行单位;进程是最小的分配资源...
  • 你必须知道的495个C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 数组大小 1.23 能否声明和传入数组大小一致的局部数组,或者由其他参数...
  • php高级开发教程说明

    2008-11-27 11:39:22
    他们都有自己 偏爱的语言(也许是公司指定的一种语言),了解它的优点和它的缺点,并根据语言的具体特点 修正项目。但当克服所选语言的缺陷时,就可能会增加不必要的额外工作。 了解如何使用一门语言却缺乏其特定的...
  • 21天学通C++ (中文第五版)

    热门讨论 2010-06-23 16:57:03
    通过阅读本书来学习C++时,读者不需要有任何编程经验。本书从入门开始,既介绍C++语言,又讨论使用C++进行编程涉及的概念。本书提供了大量语法实例和详细的代码分析,它们是引导读者完成C++编程之旅的优秀向导。无论...
  • void main() //主函数名,void 表示函数没有返回值 { //函数体标志 cout!\n"; //输出字符串Hello!到标准输出设备(显示器)上。 cout!\n"; //输出字符串Welcome to c++! } 在屏幕输出如下: Hello! Welcome to c++...
  •  本书适合于从未学习过任何编程语言的新手,以及学习c++多年,仍旧不能融会贯通的读者,对于正在使用c++进行开发的程序员也很好的参考价值。... 目录: 第1章 初识c++ .1 1.1 c++简介 1 1.2 c++与c的区别 2 ...
  • 可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。  数组大小  1.23 能否声明和传入数组大小一致的局部数组,或者由其他参数...
  • 可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 数组大小 1.23 能否声明和传入数组大小一致的局部数组,或者由其他参数...
  • o 6.13 考虑到有关空指针的所有这些困惑, 难道把要求它们内部表达必须为 0 不是更简单吗? o 6.14 说真的, 真机器用非零空指针吗, 或者不同类型用不同的表达? o 6.15 运行时的 ``空指针赋值" 错误是什么意思...
  • 可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以到无穷。 41 数组大小 42 1.23 能否声明和传入数组大小一致的局部数组,或者由其他...
  • 可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以到无穷。 41 数组大小 42 1.23 能否声明和传入数组大小一致的局部数组,或者由其他...
  • 《你必须知道的495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 12  数组大小 13 1.23 能否声明和传入数组大小一致的局部数组,或者由...
  • 可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 12  数组大小 13 1.23 能否声明和传入数组大小一致的局部数组,或者由...
  • 至此,我们了一个简单的开发环境了,可以充分利用网上大量的以oSIP为基础的代码片段和官方说明文档开始具体函数功能的测试和使用了:) --------------------------------...
  • asp.net面试题

    2011-05-27 17:56:26
    第三种:new 约束指定泛型类声明中的任何类型参数必须公共的无参数构造函数。 2.如何把一个array复制到arrayList里 foreach( object o in array )arrayList.Add(o); 3.datagrid.datasouse可以连接什么数据源 ...

空空如也

空空如也

1 2 3 4
收藏数 64
精华内容 25
关键字:

任何函数都有返回值吗