类(中)

  • 类通常应定义一个默认构造函数

为了例示需要默认构造函数的情况,假定有一个 NoDefault 类,它没有定义自己的默认构造函数,却有一个接受一个 string 实参的构造函数。

定义这样的一个类没有错,这样编译会编译成功:

class NoDefault {
public:
    void output()
    {
        cout << units_sold << endl;
    }

    NoDefault(const std::string &book) :
        isbn(book), units_sold(0), revenue(0.0) {
        cout << "first constructor" << endl;
    }
    /*NoDefault() : units_sold(0), revenue(0.0) {
        cout << "second constructor" << endl;
    }*/
private:
    std::string isbn;
    unsigned units_sold;
    double revenue;
};

int main()
{
    system("pause");
    return 0;
}

但如果定义一个对象就会报错:

因为该类定义了一个构造函数,因此编译器将不合成默认构造函数。NoDefault 没有默认构造函数,这意味着:

(1)具有 NoDefault 成员的每个类的每个构造函数,必须通过传递一个初始的 string 值给 NoDefault 构造函数来显式地初始化 NoDefault 成员

如果NoDefault有默认构造函数:

class NoDefault {
public:

    NoDefault(const std::string book) :
        isbn(book), units_sold(0), revenue(0.0) {
        cout << "NoDefault Constructor" << endl;
    }

    NoDefault() : units_sold(0), revenue(0.0) {
    cout << "NoDefault default constructor" << endl;
    }
private:
    std::string isbn;
    unsigned units_sold;
    double revenue;
};

class Sales_item {
public:
    double avg_price() const;
    bool same_isbn(const Sales_item &rhs) const
    {
        return isbn == rhs.isbn;
    }
    void output()
    {
        cout << units_sold << endl;
    }
    Sales_item(const std::string &book) :
        isbn(book), units_sold(0), revenue(0.0) {
        cout << "Sales_item constructor" << endl;
    }
    Sales_item() : units_sold(0), revenue(0.0) {
        cout << "Sales_item default constructor" << endl;
    }

private:

    std::string isbn;
    NoDefault ND;
    unsigned units_sold;
    double revenue;
};

int main()
{
    Sales_item si;
    system("pause");
    return 0;
}

输出结果:

如果NoDefault没有默认构造函数:

输出结果:

(2)编译器将不会为具有 NoDefault 类型成员的类合成默认构造函数。如果这样的类希望提供默认构造函数,就必须显式地定义,并且默认构造函数必须显式地初始化其 NoDefault 成员(如上例)指望编译器为Sales_item合成默认构造函数会报错:

class NoDefault {
public:

    NoDefault(const std::string book) :
        isbn(book), units_sold(0), revenue(0.0) {
        cout << "NoDefault Constructor" << endl;
    }
private:
    std::string isbn;
    unsigned units_sold;
    double revenue;
};

class Sales_item {
public:
    double avg_price() const;
    bool same_isbn(const Sales_item &rhs) const
    {
        return isbn == rhs.isbn;
    }
    void output()
    {
        cout << units_sold << endl;
    }

private:

    std::string isbn;
    NoDefault ND;
    unsigned units_sold;
    double revenue;
};

int main()
{
    Sales_item si;
    system("pause");
    return 0;
}

报错:

如果没有NoDefault作为Sales_item的成员,则会编译成功。

(3)NoDefault 类型的静态分配数组必须为每个元素提供一个显式的初始化式

输出结果:

如果NoDefault没有默认构造函数,则会报错:

这种数组也无法给每个NoDefault类型的成员传递初始值。

(4)NoDefault 类型的静态分配数组必须为每个元素提供一个显式的初始化式。

否则仍然会报错:

(5)如果有一个保存 NoDefault 对象的容器,例如 vector,就不能使用接受容器大小而没有同时提供一个元素初始化式的构造函数

实际上,如果定义了其他构造函数,则提供一个默认构造函数几乎总是对的。通常,在默认构造函数中给成员提供的初始值应该指出该对象是“空”的

使用默认构造函数定义一个对象的正确方法:

// ok: defines a class object ...
     Sales_item myobj;

如果定义成这样:

Sales_item myobj();   // ok: but defines a function, not an object

myobj 的定义被编译器解释为一个函数的声明,该函数不接受参数并返回一个 Sales_item 类型的对象。

这样定义也是正确的:

// ok: create an unnamed, empty Sales_itemand use to initialize myobj
     Sales_item myobj = Sales_item();

我们创建并初始化一个 Sales_item 对象,然后用它来按值初始化 myobj。编译器通过运行 Sales_item 的默认构造函数来按值初始化一个 Sales_item

  • 隐式类类型转换

C++ 语言定义了内置类型之间的几个自动转换。也可以定义如何将其他类型的对象隐式转换为我们的类类型,或将我们的类类型的对象隐式转换为其他类型。为了定义到类类型的隐式转换,需要定义合适的构造函数。可以用单个实参来调用的构造函数,定义了从形参类型到该类类型的一个隐式转换

让我们再看看定义了两个构造函数的 Sales_item 版本:

class Sales_item {
     public:
         // default argument for book is the empty string
         Sales_item(const std::string &book = ""):
                   isbn(book), units_sold(0), revenue(0.0) { }
         Sales_item(std::istream &is);
         // as before
      };

这个类中有一个成员函数

bool same_isbn(const Sales_item &rhs) const//const 成员不能改变其所操作的对象的数据成员。
        { return isbn == rhs.isbn; }

当像下面这样使用这个成员函数时,这里的每个构造函数都定义了一个隐式转换

string null_book = "9-999-99999-9";
     // ok: builds a Sales_itemwith 0 units_soldand revenue from
     // and isbn equal to null_book
     item.same_isbn(null_book);

因此,在期待一个 Sales_item 类型对象的地方,可以使用一个 string 或一个 istream

如果没有这两个构造函数,就会报错:

时间: 2024-10-08 10:42:24

类(中)的相关文章

静态修饰符static,类中的常量定义修饰符

static可以用来区分成员变量.方法是属于类本身还是属于类实例化后的对象.有static修饰的成员属于类本身,没有static修饰的成员属于类的实例. 静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失static是一个修饰符,用于修饰成员(成员变量和成员函数)静态成员随着类的加载而加载.静态成员优先于对象存在.静态成员被所有对象所共享静态成员多了一个中调用方式,可以被类名直接调用.静态的优缺点优点: 静态成员多了一种调用方式.可以直接被类名调用 格式 :类名.静态成员.也

检测某个方法是否属于某个类中--解析php函数method_exists()与is_callable()的区别

php函数method_exists() 与is_callable()的区别在哪?在php面相对象设计过程中,往往我们需要在调用某一个方法是否属于某一个类的时候做出判断,常用的方法有 method_exists()和is_callable() 相比之下,is_callable()函数要高级一些,它接受字符串变量形式的方法名作为 第一个参数,如果类方法存在并且可以调用,则返回true.如果要检测类中的方法是否能被调用,可以给函数传递一个数组而不是类的方法名作为参数.数组必须包含对象或类名,以将其作

servlet类中ServletConfig及ServletContext

在一个继承了servlet接口的类中: ServletConfig: 代表:代表了以了一个servlet标签 <servlet> <servlet-name>AServlet</servlet-name> <servlet-class>com.neuedu.path.AServlet</servlet-class> </servlet> 获取:在init方法的参数中. 作用: 获取servlet的名字(web.xml 中的对应的ser

Static在类中的作用

static 在类内用于定义静态成员.静态成员与具体的类无关,它的值及作用范围适用于所有的类,当它的值发生改变时,在所有的类中的值都会发生变化.并且,类内的Static成员,应在类外重新定义一次. 类的静态成员一般不应该在类内初始化.如初始化,必须使用constexpr进行修饰,成为一个常量. constexpr的作用是修饰一个常量,并在编译期检查一个表达式是否是常量表达式.

增强一个Java类中的某个方法的几种方式

      * 一种方式:继承的方式.  * 能够控制这个类的构造的时候,才可以使用继承. Connection是一个接口,实现类不确定(由各厂商提供),无法使用此方法     * 二种方式:装饰者模式方式.         * 包装对象和被包装的对象都要实现相同的接口.         * 包装的对象中需要获得到被包装对象的引用.         ***** 缺点:如果接口的方法比较多,增强其中的某个方法.其他的功能的方法需要原有调用.     * 三种方式:动态代理的方式.         

C++程序设计方法3:类中的静态成员

在类型前面加static修饰的数据成员,是隶属于类的,成为类的静态数据成员,也称为"类的变量" 静态数据成员被该类的所有对象共享(即所有对象中的这个数据域实际上处于同一个内存位置) 静态数据要在实现文件中赋初值,格式为: Type ClassName::static_var = Value; 返回值类型前面加static修饰的成员函数,称为静态成员函数,它们不能调用非静态成员函数: 类的静态成员(数据,函数)既可以通过对象来访问,也可以通过类名字类访问: #include <io

Kotlin操作符重载:把标准操作加入到任何类中(KAD 17)

作者:Antonio Leiva 时间:Mar 21, 2017 原文链接:https://antonioleiva.com/operator-overload-kotlin/ 就像其他每种语言一样,在Kotlin中,已经预定义了一些操作符执行一定的操作. 最典型的是加(+),减(-),乘(*),除(/),而且还有很多. 类似Java这样的一些语言,这些操作符被限制在一些特定的数量类型上,且没有方法让其他类型数据使用这些操作符. 还有在像Scala这样的其他语言中,由于函数名称可接受任何符号,我

Python类中实例属性的通用显示工具

0.说明 以下的思想方法非常有用,可以帮助你在Python开发提高开发和维护效率,所以可能的话,请仔细琢磨一下其中的代码. 之前在用Python编写一个类时,为了显示的友好性,总是需要在每个类中重载__str__或者__repr__方法,现在有了更好的方法,不需要在每个类中都这么做了,下面给出的方法非常实用. 下面使用的例子使用的Python版本都是Python3.5,但实际上在Python2.7中进行也没有任何影响. 1.正常情况下类实例的不友好显示 在Python中编写一个类时,由于没有重载

junit4 assert类中的assert方法总结

junit中的assert方法全部放在Assert类中,总结一下junit类中assert方法的分类. 1.assertTrue/False([String message,]boolean condition);判断一个条件是true还是false.感觉这个最好用了,不用记下来那么多的方法名.2.fail([String message,]);失败,可以有消息,也可以没有消息.3.assertEquals([String message,]Object expected,Object actu

python类中super()和__init__()的区别

本文和大家分享的主要是python开发中super()和__init__()的区别,希望通过本文的分享,对初学者学习这部分内容有所帮助. 1.单继承时super()和__init__()实现的功能是类似的 class Base(object): def __init__(self): print 'Base create' class childA(Base): def __init__(self): print 'creat A ', Base.__init__(self) class chi