Thread: why default assignment can NOT be used for const reference?

  1. #1
    Registered User
    Join Date
    Apr 2007
    Posts
    284

    why default assignment can NOT be used for const reference?

    The following code is incorrect. Compiler says "The default argument given for parameter 1 in foo"
    What's wrong?

    Code:
    class Base{
    virtual void foo(string str ="" )=0;
    };
    
    class Derived:public Base{
    void foo(string str ="" ){}
    };

    Anther question is that
    Code:
    void foo(const std::string& str = "")
    The compiler says it's not allowed, why is that?

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Quote Originally Posted by meili100 View Post
    The following code is incorrect. Compiler says "The default argument given for parameter 1 in foo"
    What's wrong?

    Code:
    class Base{
    virtual void foo(string str ="" )=0;
    };
    
    class Derived:public Base{
    void foo(string str ="" ){}
    };
    Pure virtual functions such as Base::foo() can never be implemented, so why should they be allowed to have default parameters? They can't.

    Anther question is that
    Code:
    void foo(const std::string& str = "")
    The compiler says it's not allowed, why is that?
    Default parameters can only be specified in function prototypes, not definitions.

    Another reason that won't compile: if a reference is to have a default value, that default value must be another variable. For example, this should work. I think. Dinkumware seems to think so, too.
    Code:
    const std::string global = "";
    void foo(const std::string& str = global) {}
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Registered User
    Join Date
    Apr 2007
    Posts
    284
    I changed the code according to your instruction
    Code:
    class Base{
    public:
    virtual void foo(string str )=0;
    };
    
    class Derived:public Base{
    public:
    void foo(string str ="" ){}
    };
    
    //in main()
    Base* ptr = new Derived;
    The complier still reports error

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Strange. Dinkumware compiles this just fine. (My additions in blue.)
    Code:
    #include <string>
    using std::string;
    class Base{
    public:
    virtual void foo(string str )=0;
    };
    
    class Derived:public Base{
    public:
    void foo(string str ="" ){}
    };
    
    int main() {
    Base* ptr = new Derived;
    }
    Can you post more of your code? What compiler are you using?
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  5. #5
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Never ever give a virtual function a default parameter. That's a totally bad idea.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by dwks View Post
    Another reason that won't compile: if a reference is to have a default value, that default value must be another variable. For example, this should work. I think. Dinkumware seems to think so, too.
    Code:
    const std::string global = "";
    void foo(const std::string& str = global) {}
    Hmmm. I can't check right now, but so far as I know, it's possible to pass empty strings to a const reference object (so I don't see why it shouldn't be possible to give an empty string as default value to a const reference string).

    Observe this:
    Code:
    void foo(CString& my_str) { // Implentation here }
    void foo2(const CString& my_str) { // Implentation here }
    int main()
    {
    	foo(""); // Compile error: must pass a variable;
    	CString my_str;
    	foo(my_str); // OK
    	foo2(""); // OK
    	return 0;
    }
    This worked last time I checked on Visual Studio.

  7. #7
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Hmmm. I can't check right now, but so far as I know, it's possible to pass empty strings to a const reference object (so I don't see why it shouldn't be possible to give an empty string as default value to a const reference string).
    Yes, as far as I know, if you take a const reference of a temporary (which the default argument is), that temporary is kept around till the end of the scope, so that should be legal.

    So you can write
    Code:
    void foo(const std::string& s = std::string());
    (Note the use of default constructor. Using "" just hides that string construction happens.)
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  8. #8
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> Pure virtual functions such as Base::foo() can never be implemented
    Yes, they can.

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Though it's not like you're going to call that pure virtual function, so there's no point in doing so.

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Though it's not like you're going to call that pure virtual function, so there's no point in doing so.
    If I remember correctly, one occasion where there is a point to it is when you have a pure virtual destructor. The destructor must still be implemented.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I find that a weird thing to do. A pure virtual constructor or destructor makes no sense since calling a pure virtual function will crash your application. Unless there's an exception to constructors/destructors?

  12. #12
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    And it's also a way to provide a default implementation that can be explicitly called by derived versions.
    Code:
    class Base
    {
    public:
      virtual void foo() = 0;
    };
    void Base::foo() {
      // Do some default action.
    }
    class Derived1 : public Base
    {
    public:
      virtual void foo() {
        // Do some preliminary work.
        Base::foo(); // Do the default thing.
      }
    };
    class Derived2 : public Base
    {
    public:
      virtual void foo() {
        // Do your own thing.
      }
    };
    Note that if you want to force the call to the base, the non-virtual interface pattern is a better solution.
    Code:
    class Base
    {
      virtual void foo_prologue() = 0;
    public:
      void foo() {
        foo_prelim();
        // Do default thing.
      }
    };
    class Derived : public Base
    {
      virtual void foo_prologue() {
        // Do preliminary work.
      }
    };
    Yes, you can override private functions if they're virtual.

    The NVI pattern is also what you should use instead of default parameters in virtual situations. Or rather, to get the default parameter away from the virtual function, where it's seriously harmful.
    Code:
    class Base
    {
      virtual void do_foo(const std::string &s);
    public:
      void foo(const std::string &s = std::string()) { do_foo(s); }
    };
    Then override do_foo in derived classes.


    A pure virtual constructor or destructor makes no sense since calling a pure virtual function will crash your application.
    Constructors can't be virtual at all. They're not part of this.
    It's not quite that simple. Doing a polymorphic call to a pure virtual function will crash your application. Doing a non-polymorphic call to the implementation will not. However, if there is no implementation, the non-polymorphic call will result in a linker error. That's why you need to implement even a pure virtual destructor.
    The real effect of a pure virtual function is not that there is no implementation. It's that the class is abstract, and all derived classes will be, too, unless they implement the function. Having a pure virtual destructor is useful when you need the class to be abstract but there's no other function you want to be pure virtual. With any other function, the derived class would have to provide an implementation, even if it did nothing but call the base version. With the destructor, such an implementation is automatically generated.
    Last edited by CornedBee; 11-29-2007 at 04:59 AM.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Elysia View Post
    I find that a weird thing to do. A pure virtual constructor or destructor makes no sense since calling a pure virtual function will crash your application. Unless there's an exception to constructors/destructors?
    The idea in this case is that you want your class to be an abstract base class, but none of the member functions are appropriate to be pure virtual. As such, you choose the destructor to be a pure virtual. However, since the derived class destructor will still invoke the base class destructor, you need to implement the base class destructor.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by laserlight View Post
    The idea in this case is that you want your class to be an abstract base class, but none of the member functions are appropriate to be pure virtual. As such, you choose the destructor to be a pure virtual. However, since the derived class destructor will still invoke the base class destructor, you need to implement the base class destructor.
    I see the logic, but you could also just creata a foo pure virtual function and override it, even if to no effect.
    But ah, still, I never thought of/knew you could do a destructor pure virtual.

  15. #15
    The larch
    Join Date
    May 2006
    Posts
    3,573
    As I understand it, instances of an abstract base class do exist - but only as a part of a derived class. You make it sound as if the abstract part of an instance was absolutely nothing.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Utilizing another compiled program for a task.
    By kotoroshinoto in forum C Programming
    Replies: 6
    Last Post: 06-03-2008, 01:43 PM
  2. Replies: 1
    Last Post: 10-27-2006, 01:21 PM
  3. C OpenGL Compiler Error?
    By Matt3000 in forum C Programming
    Replies: 12
    Last Post: 07-07-2006, 04:42 PM
  4. Constructive Feed Back (Java Program)
    By xddxogm3 in forum Tech Board
    Replies: 12
    Last Post: 10-10-2004, 03:41 AM
  5. Problem with OpenGL tutorial
    By 2Biaz in forum Windows Programming
    Replies: 18
    Last Post: 09-16-2004, 11:02 AM